#flutter #dart
#flutter #dart
Вопрос:
У меня проблема. В последние дни я играл с Flutter. Но теперь я уперся в стену. Моя проблема в том, что я нахожусь в списке (списке) внутри виджета с отслеживанием состояния. Когда я компилирую приложение, оно говорит: «Метод не найден: ‘setState'». Это имело бы смысл, если бы я был в виджете без состояния, но я нахожусь в виджете с отслеживанием состояния, поэтому он должен работать.
Это мой полный код:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() {
SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(statusBarColor: Colors.transparent));
runApp(MyApp());
}
double _value = 25.0;
bool _switchValue = false;
class MyApp extends StatefulWidget {
const MyApp();
@override
Slider createState() => Slider();
}
class Slider extends State<MyApp> {
int _selectedIndex = 0;
static const TextStyle optionStyle =
TextStyle(fontSize: 30, fontWeight: FontWeight.bold);
List<Widget> _widgetOptions = <Widget>[
Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
SizedBox(
//width: (double.infinity),
child: CupertinoSlider(
value: _value,
min: 0.0,
max: 100.0,
onChanged: (value){
setState((){
_value = value;
});
},
)
),
MergeSemantics(
child: CupertinoSwitch(
value: _switchValue,
onChanged: (value) {
setState(() {
_switchValue = value;
});
}
)
)
],
),
Text(
'Index 1: Business',
style: optionStyle,
),
];
IconData icon_calender_state = CupertinoIcons.calendar_badge_plus;
void _onItemTapped() {
setState(() {
if (_selectedIndex == 0){
_selectedIndex = 1;
icon_calender_state = CupertinoIcons.calendar_badge_minus;
return;
}
if (_selectedIndex == 1){
_selectedIndex = 0;
icon_calender_state = CupertinoIcons.calendar_badge_plus;
return;
}
});
}
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Welcome to Flutter',
home: Scaffold(
body: Stack(
children: <Widget>[
Center(
child: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topRight,
end: Alignment.bottomLeft,
colors: [Colors.blue, Colors.red])),
child: Center(
child: _widgetOptions.elementAt(_selectedIndex),
))),
Align(
alignment: Alignment.bottomLeft,
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
IconButton(icon: Icon(icon_calender_state), onPressed: () {
_onItemTapped();
},),
],)),
],
)));}
}
И это только та часть, в которой заключается ошибка. Каждый вызов setState внутри следующего списка возвращает указанную ошибку.
class Slider extends State<MyApp> {
int _selectedIndex = 0;
static const TextStyle optionStyle =
TextStyle(fontSize: 30, fontWeight: FontWeight.bold);
List<Widget> _widgetOptions = <Widget>[
Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
SizedBox(
//width: (double.infinity),
child: CupertinoSlider(
value: _value,
min: 0.0,
max: 100.0,
onChanged: (value){
setState((){
_value = value;
});
},
)
),
MergeSemantics(
child: CupertinoSwitch(
value: _switchValue,
onChanged: (value) {
setState(() {
_switchValue = value;
});
}
)
)
],
),
Text(
'Index 1: Business',
style: optionStyle,
),
];
У кого-нибудь есть идея, почему это происходит? Есть предложения, как мне следует изменить свой код?
Ответ №1:
Вы придерживаетесь плохой практики для flutter и храните виджеты внутри переменной. Обычно это большой запрет, поскольку виджеты неизменяемы и не будут обновляться так, как вы ожидаете.
Либо объявите List
внутри build
, либо измените его на функцию, которая вместо этого возвращает a List
, которая вызывается в build
List<Widget> _widgetOptions() {
return <Widget>[
Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
SizedBox(
//width: (double.infinity),
child: CupertinoSlider(
value: _value,
min: 0.0,
max: 100.0,
onChanged: (value){
setState((){
_value = value;
});
},
)
),
MergeSemantics(
child: CupertinoSwitch(
value: _switchValue,
onChanged: (value) {
setState(() {
_switchValue = value;
});
}
)
)
],
),
Text(
'Index 1: Business',
style: optionStyle,
),
];
}
Комментарии:
1. Спасибо. Я попробовал ваше предложение, используя функцию, но проблема заключалась в том, что я не мог получить к ней доступ с помощью индекса. Но затем я попытался объявить его внутри сборки, и это сработало. Спасибо: D
2. @JuliusWaldmann Если мой ответ помог, пожалуйста, отметьте его как принятый. Что касается проблемы с функцией, вы, вероятно, неправильно вызывали функцию и пытались получить доступ к индексу ссылки на функцию вместо возвращаемого значения функции.
Ответ №2:
В ответе Кристофера рассказывается, как устранить проблему, но на самом деле проблема заключалась в том, что вы вызываете setState
внутри инициализатора для поля _widgetOptions
класса. Вы не можете использовать ни один из членов класса в инициализаторе в этом классе, который не отмечен static
или иным образом доступен из статического контекста (т. Е. Без this
явного или неявного вызова). Поскольку setState
это метод экземпляра и к нему должен быть получен доступ путем (неявного) вызова this
, он еще не существует при _widgetOptions
инициализации.
Например, возьмем следующее:
class Foo {
// An instance method that does not exist until the constructor is called
// and all instance initializers have run
int a() { return 2; }
// A static method that is created at the same time as the class type itself
// and exists before any constructors and instance initializers have run
static int b() { return 3; }
// This is fine
int x = b();
// This is also fine
int y;
void doSomething() {
y = a();
}
// This will throw an error because `this` does not yet exist when `z`
// gets initialized and calling `a()` implicitly becomes `this.a()`
int z = a();
}
Перемещение инициализатора в build
метод или преобразование его в сам метод, как предлагает Кристофер, решит проблему.
Комментарии:
1. Вы можете использовать неконстантные или нестатические значения в инициализаторе. Проблема здесь в том, что для этого требуется доступ к
this
, который не существует во время инициализации поля, поскольку они выполняются перед конструктором, и вы упомянули, но говорить, что нельзя использовать значения, которые не являются постоянными или статическими в инициализаторе, немного вводит в заблуждение.2. @ChristopherMoore Что я имел в виду (и, возможно, плохо объяснил), так это то, что все, что используется, должно быть доступно из статического контекста (т. Е. Без
this
явных или неявных ссылок), и что это означает в отношении использования членов класса в инициализаторе, так это то, что они должны быть помечены как либоstatic
илиconst
(что я предполагаюявляется избыточным, посколькуconst
члены класса также должны быть отмеченыstatic
).