【问题标题】:Why does my statefull widget not rebuild properly after setState() in flutter?为什么我的有状态小部件在 setState() 后无法正确重建?
【发布时间】:2020-07-15 20:36:46
【问题描述】:

我有一个有状态的小部件“对话”,它从其父级获取“事件”。此事件有一个 initStateID 和许多其他状态。我正在尝试使用 setState() 函数在这些状态中循环,以更改 statefull 小部件“Dialogue”的属性“_currentState”。

当我点击一个按钮时,状态应该会改变。控制台打印以下行:

打印细节...

I/flutter (5101): 当前状态 id: 10011 I/flutter (5101): next id: 10010 I/flutter (5101): 新状态 id: 10010 I/flutter (5101): 当前状态ID:10010

但小部件树不会改变。我什至制作了一个“_helpfunction”并将其分配给第四个按钮。当我在调用 setState() 后单击它时,_currentState 又回到了 10011。

I/flutter (5101): currentstateid: 10011

在我看来,每当我触发重建功能时,'_currentState' 都会将自身设置回 initState。我该如何解决这个问题? 我已经尝试了好几个小时,所以感谢您的帮助!

代码如下:

    class Encounter extends StatefulWidget {
  @override
  _State createState() => _State();
}

class _State extends State<Encounter> {
  Event _currentEvent;

  @override
  Widget build(BuildContext context) {
    _currentEvent =
        DataStorage.events[new Random().nextInt(DataStorage.EVENTCOUNT)];

    return Dialogue(firstEvent: _currentEvent);
  }
}

class Dialogue extends StatefulWidget {
  Dialogue({Key key, this.firstEvent}) : super(key: key);
  Event firstEvent;
  @override
  _DialogueState createState() => _DialogueState();
}

class _DialogueState extends State<Dialogue> {
  @override
  Widget build(BuildContext context) {
    EventState _currentState = (DataStorage.eventStates
        .singleWhere((f) => f.id == widget.firstEvent.initStateID));

    void _helpfunction(ButtonData data) {
      print("currentstateid: ${_currentState.id}");
    }


    void _advance(ButtonData data) {
      print('printing details...');
      print("current state id: ${_currentState.id}");
      print("next id: ${data.nextID}");

      final _newState = (DataStorage.eventStates.singleWhere((f) => f.id == data.nextID));
      print("new state id: ${_newState.id}");
      setState(() {
        _currentState = _newState;
        print("current state id: ${_currentState.id}");
      });
      //tady se muze delat cokoli s informacema od ButtonData
    }

    return SafeArea(
        child: Container(
      color: Colors.white,
      child: Column(
        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
        crossAxisAlignment: CrossAxisAlignment.center,
        children: <Widget>[
          Text(
            widget.firstEvent.personName,
            style: TextStyle(
              fontSize: 26,
              color: Colors.black,
              fontWeight: FontWeight.bold,
              decoration: TextDecoration.none,
            ),
          ),
          Image.asset(
            widget.firstEvent.imagePath,
            height: 300,
          ),
          Container(
            decoration: BoxDecoration(
                borderRadius: BorderRadius.circular(4.0),
                border: Border.all(width: 2.0, color: Colors.black)),
            child: Padding(
              padding: EdgeInsets.all(5.0),
              child: Text(
                _currentState.sentence,
                style: TextStyle(
                  fontSize: 18,
                  color: Colors.black,
                  decoration: TextDecoration.none,
                ),
              ),
            ),
          ),
          Table(
            defaultVerticalAlignment: TableCellVerticalAlignment.middle,
            children: [
              TableRow(
                children: [
                  ReactionButton(
                    source: _currentState.butt1,
                    advance: _advance,
                  ),
                  ReactionButton(
                    source: _currentState.butt2,
                    advance: _advance,
                  ),
                ],
              ),
              TableRow(
                children: [
                  ReactionButton(
                    source: _currentState.butt3,
                    advance: _advance,
                  ),
                  ReactionButton4(
                    source: _currentState.butt4,
                    helpfunction: _helpfunction,
                  ),
                ],
              ),
            ],
          )
        ],
      ),
    ));
  }
}

反应按钮:

class ReactionButton extends StatelessWidget {
  ReactionButton({Key key, this.source, this.advance}) : super(key: key);
  final Function advance;
  final ButtonData source;

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: EdgeInsets.symmetric(horizontal: 5.0),
      child: FlatButton(
        padding: EdgeInsets.all(5.0),
        color: Colors.blue,
        child: Text(
          source.text,
        ),
        onPressed: () {
          advance(source);
        },
      ),
    );
  }
}

ReactionButton4 类似,但在点击时会调用“_helpfunction”。

这是我存储的数据的样子:

static List<Event> events = [
    Event(
      id: 100,
      personName: 'Batman',
      imagePath: 'images/batman.png',
      initStateID: 10011,
    ),
    Event(
      id: 101,
      personName: 'Kocka',
      imagePath: 'images/kocka.jpg',
      initStateID: 10110,
    ),
  ];

  static List<EventState> eventStates = [
    EventState(
      id: 10010,
      sentence: "sentence",
      butt1: ButtonData(text: '1', nextID: 10011),
      butt2: ButtonData(text: '2', nextID: 10011),
      butt3: ButtonData(text: '3', nextID: 10011),
      butt4: ButtonData(text: '4', nextID: 10011),
    ),
    EventState(
      id: 10011,
      sentence: "?!?!?",
      butt1: ButtonData(text: 'a', nextID: 10010),
      butt2: ButtonData(text: 'b', nextID: 10010),
      butt3: ButtonData(text: 'c', nextID: 10010),
      butt4: ButtonData(text: 'd', nextID: 10010),
    ),
    EventState(
      id: 10110,
      sentence: "Mnau1",
      butt1: ButtonData(text: '1', nextID: 10111),
      butt2: ButtonData(text: '2', nextID: 10111),
      butt3: ButtonData(text: '3', nextID: 10111),
      butt4: ButtonData(text: '4', nextID: 10111),
    ),
    EventState(
      id: 10111,
      sentence: "Mnau2",
      butt1: ButtonData(text: 'a', nextID: 10110),
      butt2: ButtonData(text: 'b', nextID: 10110),
      butt3: ButtonData(text: 'c', nextID: 10110),
      butt4: ButtonData(text: 'd', nextID: 10110),
    ),
  ];
}

【问题讨论】:

    标签: flutter state


    【解决方案1】:

    您在每次重建时重置您的 _currentState 变量。调用setState后,Widget会自动重建。因此,您正确设置了 _currentState 变量,但一旦调用 build 函数,它就会重置为初始状态。

    您必须从构建函数中获取变量并且必须设置它,例如在类的initState 函数中。尝试对 Dialogue 类进行以下更改

    class Dialogue extends StatefulWidget {
      Dialogue({Key key, this.firstEvent}) : super(key: key);
      Event firstEvent;
      @override
      _DialogueState createState() => _DialogueState();
    }
    
    class _DialogueState extends State<Dialogue> {
      EventState _currentState  
    
      @override
      void initState() {
        super.initState();
        _currentState = (DataStorage.eventStates
            .singleWhere((f) => f.id == widget.firstEvent.initStateID));
      }
    
      @override
      Widget build(BuildContext context) {
        void _helpfunction(ButtonData data) {
          print("currentstateid: ${_currentState.id}");
        }
      ...
    

    【讨论】:

    • 谢谢!你的建议有效!我也尝试了一些 initState 魔法,但最终尝试定义变量 _currentState 两次。一次进入initState,一次进入状态构建函数,我很困惑。
    • @VláďaHořký 是我为你工作的答案,那么请在帖子上打勾接受它。谢谢
    猜你喜欢
    • 1970-01-01
    • 2020-10-19
    • 2020-04-25
    • 1970-01-01
    • 2021-06-15
    • 2021-09-15
    • 2019-03-28
    • 2020-04-17
    • 2018-02-06
    相关资源
    最近更新 更多