這次是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();
},
)),
);
}
}
複製程式碼
再次執行,對話方塊中的核取方塊可以正常響應。至此,問題解決。