Auf den Kontext der Mitgliedsvariablen kann während zugegriffen werden initState
, er kann jedoch nicht für alle verwendet werden. Dies ist aus dem Flattern zur initState
Dokumentation:
Sie können [BuildContext.inheritFromWidgetOfExactType]
diese Methode nicht verwenden . Allerdings [didChangeDependencies]
wird genannt nach dieser Methode sofort und [BuildContext.inheritFromWidgetOfExactType]
kann dort verwendet werden.
Sie können Ihre Initialisierungslogik auf verschieben didChangeDependencies
, dies ist jedoch möglicherweise nicht genau das, was Sie möchten, da didChangeDependencies
dies im Lebenszyklus des Widgets mehrmals aufgerufen werden kann.
Wenn Sie stattdessen einen asynchronen Anruf tätigen, der Ihren Anruf delegiert, bis das Widget initialisiert wurde, können Sie den Kontext wie beabsichtigt verwenden.
Ein einfacher Weg, dies zu tun, besteht darin, eine Zukunft zu nutzen.
Future.delayed(Duration.zero,() {
... showDialog(context, ....)
}
Eine andere Möglichkeit, die möglicherweise „korrekter“ ist, besteht darin, den Flutter-Scheduler zu verwenden, um einen Post-Frame-Rückruf hinzuzufügen:
SchedulerBinding.instance.addPostFrameCallback((_) {
... showDialog(context, ....)
});
Und zum Schluss noch ein kleiner Trick, den ich gerne mache, um asynchrone Aufrufe in der initState-Funktion zu verwenden:
() async {
await Future.delayed(Duration.zero);
... showDialog(context, ...)
}();
Hier ist ein vollständig ausgearbeitetes Beispiel mit dem einfachen Future.delayed:
import 'dart:async';
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
bool _checkConfiguration() => true;
void initState() {
super.initState();
if (_checkConfiguration()) {
Future.delayed(Duration.zero,() {
showDialog(context: context, builder: (context) => AlertDialog(
content: Column(
children: <Widget>[
Text('@todo')
],
),
actions: <Widget>[
FlatButton(onPressed: (){
Navigator.pop(context);
}, child: Text('OK')),
],
));
});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.display1,
),
],
),
),
);
}
}
Mit mehr Kontext aus dem OP in den Kommentaren kann ich eine etwas bessere Lösung für ihr spezifisches Problem geben. Abhängig von der App möchten Sie möglicherweise tatsächlich eine Entscheidung treffen, die darauf basiert, welche Seite angezeigt werden soll, je nachdem, ob die App zum ersten Mal geöffnet wird, dh home
auf etwas anderes eingestellt ist. Und Dialoge sind nicht unbedingt das beste UI-Element auf Mobilgeräten. Es ist möglicherweise besser, eine vollständige Seite mit den Einstellungen anzuzeigen, die hinzugefügt werden müssen, sowie eine Schaltfläche "Weiter".
MaterialApp
diehome
Eigenschaft von aufgerufen . Also mache ich dort nicht wirklich einen Push. Können Sie mir ein Beispiel geben, wie es in derbuild
Funktion geht? Derzeit gibt es nur eine neueScaffold
mit einappBar
,drawer
,body
undfloatingActionButton
Scaffold
anzuzeigen (als keine Modal), wenn die Prüfung fehlschlägt und ansonsten nur die Homepage anzuzeigen. Das fühlt sich für mich jedoch irgendwie hackig an.didChangeDependencies
Methodecontext
tatsächlich eine Mitgliedsvariable des Zustands = D ist. Damit Sie den BooleschenFuture.delayed
Wert nicht benötigen, können Sie ihn einfach direkt in Ihrem Initstate verwenden. Dies ist jedoch weiterhin erforderlich. Ohne diese Fehler werden beim Versuch, während eines Pushs zu pushen, Bestätigungsfehler angezeigt.Einwickeln mit
Future
@override void initState() { super.initState(); _store = Store(); new Future.delayed(Duration.zero,() { _store.fetchContent(context); }); }
quelle
Wir können den globalen Schlüssel verwenden als:
class _ContactUsScreenState extends State<ContactUsScreen> { //Declare Global Key final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>(); //key Widget build(BuildContext context) { return Scaffold( key: _scaffoldKey, appBar: AppBar( title: Text('Contact Us'), ), body: } //use Future<void> send() async { final Email email = Email( body: _bodyController.text, subject: _subjectController.text, recipients: [_recipientController.text], attachmentPaths: attachments, isHTML: isHTML, ); String platformResponse; try { await FlutterEmailSender.send(email); platformResponse = 'success'; } catch (error) { platformResponse = error.toString(); } if (!mounted) return; _scaffoldKey.currentState.showSnackBar(SnackBar( content: Text(platformResponse), )); } }
quelle
Einfache Verwendung
Timer.run()
@override void initState() { super.initState(); Timer.run(() { // you have a valid context here }); }
quelle