我正在创建一个Flutter应用程序,用于存储棋盘游戏角色的进度,我希望允许用户最多检查18个复选框,其中这些复选框分为三部分:
我的第一种方法是对该小部件进行编码,以使我尽可能少地重用代码。
CheckboxGroup
是一个Row
小部件,带有复选标记图标“:”和三个复选框作为子级。
CheckboxGridRow
是一个Row
小部件,其中有两个CheckboxGroup
作为子级。
CheckboxGrid
是一个Column
小部件,其中三个CheckboxGridRows
作为子级。
-> CheckboxGrid
-> CheckboxGridRow
-> CheckboxGroup
-> CheckboxGroup
-> CheckboxGridRow
-> CheckboxGroup
-> CheckboxGroup
-> CheckboxGridRow
-> CheckboxGroup
-> CheckboxGroup
这对于UI来说很好用,但是我正在努力地思考如何管理/存储状态。我希望我将使用List<bool>
来存储状态的true / false,但是此设置的状态更改和数据库逻辑应该放在哪里?
答案 0 :(得分:0)
在Flutter中,状态仅沿树下降。因此,解决方案不多:
状态必须由所有复选框的共同祖先存储。
从那里,很容易推断出“复选框”和“复选框组”应该做什么:UI
没什么特别的。只要具有,任何复选框都可以:
此小部件会将选项列表映射到复选框列表中,并确定是否选中了这些选项。
通常具有三个参数:
这是一个典型的实现方式:
@immutable
class Option<T> {
Option({@required this.value, @required this.label});
final T value;
final Widget label;
}
class CheckboxGroup<T> extends StatelessWidget {
CheckboxGroup({
Key key,
@required this.options,
@required this.selectedValues,
@required this.onChange,
}) : super(key: key);
final List<Option<T>> options;
final List<T> selectedValues;
final ValueChanged<List<T>> onChange;
@override
Widget build(BuildContext context) {
return Row(
children: <Widget>[
for (final option in options) ...[
Checkbox(
key: ObjectKey(option.value),
value: selectedValues.contains(option.value),
onChanged: (res) {
if (res) {
onChange([...selectedValues, option.value]);
} else {
onChange([...selectedValues]..remove(option.value));
}
},
),
option.label,
]
],
);
}
}
与之前的代码段相比,它非常简单:
它只是声明了一堆字段,将它们发送到CheckboxGroup
,并在需要时调用setState
。
enum Foo { a, b, c }
enum Bar { a, b, c }
class Example extends StatefulWidget {
@override
_ExampleState createState() => _ExampleState();
}
class _ExampleState extends State<Example> {
List<Foo> foo = const [];
List<Bar> bar = const [];
@override
Widget build(BuildContext context) {
return ListView(
children: <Widget>[
CheckboxGroup<Foo>(
selectedValues: foo,
options: [
for (final value in Foo.values)
Option(value: value, label: Text(value.toString()))
],
onChange: (value) => setState(() => foo = value),
),
CheckboxGroup<Bar>(
selectedValues: bar,
options: [
for (final value in Bar.values)
Option(value: value, label: Text(value.toString()))
],
onChange: (value) => setState(() => bar = value),
),
],
);
}
}