如何管理/保存具有许多复选框的小部件的状态?

时间:2019-08-26 21:17:06

标签: checkbox flutter state

我正在创建一个Flutter应用程序,用于存储棋盘游戏角色的进度,我希望允许用户最多检查18个复选框,其中这些复选框分为三部分:

example

我的第一种方法是对该小部件进行编码,以使我尽可能少地重用代码。

CheckboxGroup是一个Row小部件,带有复选标记图标“:”和三个复选框作为子级。 CheckboxGridRow是一个Row小部件,其中有两个CheckboxGroup作为子级。 CheckboxGrid是一个Column小部件,其中三个CheckboxGridRows作为子级。

-> CheckboxGrid
  -> CheckboxGridRow
    -> CheckboxGroup
    -> CheckboxGroup
  -> CheckboxGridRow
    -> CheckboxGroup
    -> CheckboxGroup
  -> CheckboxGridRow
    -> CheckboxGroup
    -> CheckboxGroup

这对于UI来说很好用,但是我正在努力地思考如何管理/存储状态。我希望我将使用List<bool>来存储状态的true / false,但是此设置的状态更改和数据库逻辑应该放在哪里?

1 个答案:

答案 0 :(得分:0)

在Flutter中,状态仅沿树下降。因此,解决方案不多:

状态必须由所有复选框的共同祖先存储。

从那里,很容易推断出“复选框”和“复选框组”应该做什么:UI


复选框小部件

没什么特别的。只要具有,任何复选框都可以:

  • “选中的”布尔值
  • “ onChanged”回调。

默认的CheckboxSwitch应该可以。

复选框组

此小部件会将选项列表映射到复选框列表中,并确定是否选中了这些选项。

通常具有三个参数:

  • 所有选项的列表
  • 所选选项列表
  • “ onChanged”回调

这是一个典型的实现方式:

@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),
        ),
      ],
    );
  }
}