Ошибка: в инициализаторы могут быть доступны только статические члены, что это значит?
У меня есть что-то вроде этого. Мне трудно понять эту ошибку. Почему здесь обращение к filterController
дает здесь эту ошибку? но он не дает эту ошибку, если я перемещаю текущее целое создание TextFormField
(между комментариями A и B) внутри метода сборки? Как перемещение всего TextFormField
внутри метода сборки делает filterController
static и разрешает эту проблему?
class AppHomeState extends State<AppHome> with SingleTickerProviderStateMixin
{
TabController _tabController;
final filterController = new TextEditingController(text: "Search");
//----A
TextFormField email = new TextFormField(
keyboardType: TextInputType.emailAddress,
controller: filterController, ------>ERROR : Error: Only static members can be accessed in initializers
);
//----B
@override
Widget build(BuildContext context)
{
return new Scaffold(
appBar: new AppBar(..),
);
}
}
Как я могу решить эту проблему?
Ответы
Ответ 1
class AppHomeState extends State<AppHome> with SingleTickerProviderStateMixin {
TabController _tabController;
final filterController = new TextEditingController(text: "Search");
TextFormField email = ...
...
это инициализатор и нет никакого способа, чтобы получить доступ к this
в этой точке. Инициализаторы выполняются перед конструктором, но this
разрешено только после того, как вызов супер-конструктора (неявный в вашем примере) был завершен. Поэтому только в теле конструктора (или позже) доступ к this
разрешен.
Вот почему вы получаете сообщение об ошибке:
controller: filterController,
обращается к this.filterController
(this
неявно, если вы не пишете его явно).
Чтобы обойти проблему (при условии, что email
должна быть final
), вы можете использовать заводский конструктор и список инициализаторов конструктора:
class AppHomeState extends State<AppHome> with SingleTickerProviderStateMixin {
factory SingleTickerProviderStateMixin() =>
new SingleTickerProviderStateMixin._(new TextEditingController(text: "Search"));
SingleTickerProviderStateMixin._(TextEditingController textEditingController) :
this.filterController = textEditingController,
this.email = new TextFormField(
keyboardType: TextInputType.emailAddress,
controller: textEditingController);
TabController _tabController;
final filterController;
final TextFormField email;
или когда поле email
не обязательно должно быть окончательным, email
может быть инициализирована в списке инициализаторов конструктора:
class AppHomeState extends State<AppHome> with SingleTickerProviderStateMixin {
SingleTickerProviderStateMixin() {
email = new TextFormField(
keyboardType: TextInputType.emailAddress,
controller: filterController,
);
}
TabController _tabController;
final filterController = new TextEditingController(text: "Search");
TextFormField email;
но в виджетах initState
обычно используется для этого
class AppHomeState extends State<AppHome> with SingleTickerProviderStateMixin {
@override
void initState() {
super.initState();
email = new TextFormField(
keyboardType: TextInputType.emailAddress,
controller: filterController,
);
}
TabController _tabController;
final filterController = new TextEditingController(text: "Search");
TextFormField email;
Ответ 2
Вы можете сохранить это как метод:
Widget getEmailController(){
return new
TextFormField email = new TextFormField(
keyboardType: TextInputType.emailAddress,
controller: filterController,
);
}
и используйте его в пользовательском интерфейсе:
body: Container(
child: getEmailController();
)
Ответ 3
Вы можете преобразовать эту переменную в функцию, и вы можете использовать контекст в этих параметрах функции.
пример
Widget myDialog (BuildContext context) {
return new Scaffold(
backgroundColor: Colors.white,
body: new Center(
child: new Column(
children: <Widget>[
new Text("Invalid Username/Password"),
new Text("Please verify your login credentials"),
new RaisedButton(
child: new Text("Ok"),
onPressed:() {
Navigator.pop(context);//Error : Only static members can be accessed in initializers
}
),
],
),
)
);
}
// Using if you are doing in a class
this.myDialog(context);
// Using if you are using a global function
myDialog(context);
Но, я думаю, вы хотите показать сообщение об ошибке. Таким образом, вы можете сделать это с помощью диалога, а не страницы. Это более эффективно, потому что вы можете указать свое диалоговое окно с помощью кнопок или сообщений, и вы можете использовать это диалоговое окно ошибок повсюду. Давайте посмотрим на мою глобальную вспомогательную функцию для отображения сообщений об ошибках.
void showError(BuildContext context, String error) {
showSnackBar(
context,
new Text(
'Error',
style: new TextStyle(color: Theme.of(context).errorColor),
),
content: new SingleChildScrollView(
child: new Text(error)
),
actions: <Widget>[
new FlatButton(
child: new Text(
'Ok',
style: new TextStyle(
color: Colors.white
),
),
onPressed: () {
Navigator.of(context).pop();
},
color: Theme.of(context).errorColor,
),
]
);
}
// Using in everywhere
showError(context, 'Sample Error');