在Flutter中使用SetState无效?可能是忽略了这个!

Posted 萧文翰

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在Flutter中使用SetState无效?可能是忽略了这个!相关的知识,希望对你有一定的参考价值。

这次是Flutter开发技术分享,解决的问题点来自本人实际的开发经历。
首先描述一下问题:在某个组件中调用setState()方法更新该组件状态,结果是无法做到更新效果,组件仍然维持原状。
下面我们用代码示例还原问题场景:

class _MyHomePageState extends State<MyHomePage> 
  bool isChecked = false;

  showTestDialog() 
    showDialog(
      context: context,
      builder: (BuildContext context) 
        return SimpleDialog(title: Text("测试对话框标题"), children: <Widget>[
          Row(children: <Widget>[
            Checkbox(
                value: this.isChecked,
                onChanged: (bool val) 
                  setState(() 
                    this.isChecked = !this.isChecked;
                  );
                  debugPrint(this.isChecked.toString());
                ),
            Text("测试复选框")
          ])
        ]);
      ,
    );
  

  @override
  Widget build(BuildContext context) 
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
          child: RaisedButton(
        child: Text("点击出现弹窗"),
        onPressed: () 
          showTestDialog();
        ,
      )),
    );
  

为了突出问题点,减少不必要的干扰,我简化了原有代码内容。通过阅读上述代码,我们得知整个Demo的界面有一个按钮构成,当按钮被点击时,showTestDialog()方法被执行。界面将显示一个小窗口,里面有一个复选框。
我们要实现的效果当然是用户点击复选框的时候,改变复选框的状态。因此,在复选框的onChanged()方法中改变了决定复选框状态的布尔值,并setState()。
然而真实的运行结果并非像预期那样产生效果。
究其原因,我们还需从setState()说起。
顾名思义,setState()要求其作用对象必须是一个有状态的组件。如果作用对象本身无状态,那么setState()将无法起作用。
因此,我们找到原因:SimpleDialog()中的子组件默认是无状态的。
接下来的解决办法就简单了,只需要在SimpleDialog组件外部“套”一个StatefulBuilder组件即可。参考下面的代码:

class _MyHomePageState extends State<MyHomePage> 
  bool isChecked = false;

  showTestDialog() 
    showDialog(
      context: context,
      builder: (BuildContext context) 
        return StatefulBuilder(
          builder:
              (BuildContext context, void Function(void Function()) setState) 
            return SimpleDialog(title: Text("测试对话框标题"), children: <Widget>[
              Row(children: <Widget>[
                Checkbox(
                    value: this.isChecked,
                    onChanged: (bool val) 
                      setState(() 
                        this.isChecked = !this.isChecked;
                      );
                      debugPrint(this.isChecked.toString());
                    ),
                Text("测试复选框")
              ])
            ]);
          ,
        );
      ,
    );
  

  @override
  Widget build(BuildContext context) 
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
          child: RaisedButton(
        child: Text("点击出现弹窗"),
        onPressed: () 
          showTestDialog();
        ,
      )),
    );
  

再次运行,对话框中的复选框可以正常响应。至此,问题解决。

以上是关于在Flutter中使用SetState无效?可能是忽略了这个!的主要内容,如果未能解决你的问题,请参考以下文章

在构建期间调用 setState() 或 markNeedsBuild() - Flutter

什么时候在 Flutter 中使用 setState?

Flutter :setState() 或 markNeedsBuild() 在构建期间调用

Flutter:我可以在 BLoC 架构中使用 setState() 吗?

编辑文本控制器更新小部件值而不调用 setState() - Flutter

成员 'setState' 只能在 'package:flutter/src/widgets/framework.dart' 的子类的实例成员中使用