這次是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();
},
)),
);
}
}
再次運行,對話框中的復選框可以正常響應。至此,問題解決。