Ответ 1
Контекст переменной-члена может быть доступен во время initState
, но не может использоваться для всего. Это из флаттера документации initState
:
Вы не можете использовать
[BuildContext.inheritFromWidgetOfExactType]
из этого метод. Однако,[didChangeDependencies]
будет вызван немедленно следуя этому методу, и[BuildContext.inheritFromWidgetOfExactType]
можно использовать там.
Вы можете переместить логику инициализации на didChangeDependencies
, однако это может быть не совсем то, что вам нужно, поскольку didChangeDependencies
можно вызывать несколько раз в жизненном цикле виджета.
Если вместо этого вы делаете асинхронный вызов, который делегирует ваш вызов до тех пор, пока виджет не будет инициализирован, вы можете использовать контекст по своему усмотрению.
Простой способ сделать это - использовать будущее.
Future.delayed(Duration.zero,() {
... showDialog(context, ....)
}
Другой способ, который может быть более "правильным", - это использовать планировщик флаттера для добавления обратного вызова после фрейма:
SchedulerBinding.instance.addPostFrameCallback((_) {
... showDialog(context, ....)
});
И, наконец, вот небольшая хитрость, которую я хотел бы сделать, чтобы использовать асинхронные вызовы в функции initState:
() async {
await Future.delayed(Duration.zero);
... showDialog(context, ...)
}();
Вот полностью проработанный пример с использованием простого 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,
),
],
),
),
);
}
}
С большим количеством контекста из OP, предоставленного в комментариях, я могу дать немного лучшее решение их конкретной проблемы. В зависимости от приложения вы можете захотеть принять решение на основе того, какую страницу показывать, в зависимости от того, открывается ли она в первый раз, то есть установить home
на что-то другое. И диалоги не обязательно являются лучшим элементом пользовательского интерфейса на мобильных устройствах; может быть лучше показать полную страницу с настройками, которые им нужно добавить, и кнопку "Далее".