在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();
        },
      )),
    );
  }
}

再次運行,對話框中的復選框可以正常響應。至此,問題解決。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM