Метод не найден: ‘setState’, хотя я в виджете с отслеживанием состояния

#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 ).