读状态小部件的状态

时间:2018-04-30 01:34:23

标签: dart flutter

我一直在用Flutter慢慢构建一个应用程序,并且正在努力在StatefulWidget / State范例下工作。

我习惯于能够从其他类中读取或更改某些UI组件的状态,并且不太了解如何在Flutter中执行此操作。例如,现在我正在构建一个包含CheckBoxListTiles的ListView。我想从另一个班级中查看列表区块中每个复选框的状态。

我觉得这在实践中应该非常简单,但是我无法想出一个方法或一个例子来有效地外化给定Widget的状态,以便它可以在其他地方使用。我知道在明显的困难背后可能有一个有意和哲学的原因,我自己也可以看到为什么它在Flutter这样的框架中至关重要的原因。然而,我觉得受到限制的是,对于一个新人来说,如何在蝙蝠范式下进行工作并不明显。

如何从ItemsList类中读取复选框的值?

Item类:

class ItemsList extends StatefulWidget {

  @override
  State<StatefulWidget> createState() => new ItemsListState();

}

class ItemsListState extends State<ItemsList> {

  List<ListItem> _items = new List();

  @override
  Widget build(BuildContext context) {

    return new Scaffold(

      body: new ListView(
        children: _items.map((ListItem item) {
          return item;
        }).toList(),
      ),

      floatingActionButton: new FloatingActionButton(
        onPressed: addItem,
        child: new Icon(Icons.add),),

    );
  }

  void addItem() {
    setState(() {
      _items.add(new ListItem("Item"));
    });
  }

  List<String> getSelectedTitles() {
    List<String> selected = new List();

        ***This is where I would like to externalize the state***

    for(ListItem e in _items) {
      if(e.isSelected()) {
        selected.add(e.getTitle());
      }
    }

    return selected;
  }

  @override
  void initState() {
    super.initState();
  }

  @override
  void dispose() {
    super.dispose();
  }

}

列表类:

$variable = array(...);

1 个答案:

答案 0 :(得分:4)

Flutter与您的常用应用程序不同。它使用类似于react的原理,它们本身与函数式编程类似。

这意味着飘飘带来了一系列限制,迫使您以不同的方式构建应用程序:

  • 小部件是不可变的。你不能更新它们。你重新创建它们。
  • 您无法访问孩子的。您只能从父母那里访问数据/状态。

作为奖励,你几乎可以肯定任何事件都不会对另一个不相关的阶级产生隐含的未知后果。

Okey,但这对我的例子有什么影响?

这非常直截了当:这意味着说出一个列表的不可能,可以从列表项之一访问信息。

您应该做的事情恰恰相反:将所有列表项的信息存储在列表中。并将其传递给每个人。

首先,我们需要更改ListItem,以便从父母那里获取所有内容。我们也可以将其变为无国籍,因为它不再存储任何信息。

有了这些,ListItem突然变得非常简单:

class ListItem extends StatelessWidget {
  final String title;
  final bool isSelected;
  final ValueChanged<bool> onChange;

  ListItem({ @required this.onChange, this.title = "", this.isSelected = false, });

  @override
  Widget build(BuildContext context) {
    return new CheckboxListTile(
      title: new Text(title),
      value: isSelected,
      onChanged: onChange
    );
  }
}

请注意,所有字段都是不可变的。并且传递给onChange的{​​{1}}事件也作为参数传递!

此时你可能会认为&#34;但现在这个班级没有多大意义#34; ? 并不是的。在我们的例子中,布局很简单。但是这是一个很好的做法来创建这样的类,因为它分割布局。清除布局逻辑的父代码。

无论如何,让我们继续。

现在,让我们修改父级,使其包含信息并将其传递下去:

CheckboxListTile

请注意,我不是在改变class ItemsList extends StatefulWidget { State<StatefulWidget> createState() => new ItemsListState(); } class ItemsListState extends State<ItemsList> { List<ListItem> items = new List<ListItem>(); @override Widget build(BuildContext context) { return new Scaffold( body: new ListView( children: items, ), floatingActionButton: new FloatingActionButton( onPressed: addItem, child: new Icon(Icons.add), ), ); } void addItem() { final listItemIndex = items.length; final newList = new List<ListItem>.from(items) ..add( new ListItem( onChange: (checked) => onListItemChange(listItemIndex, checked), title: "Item n' $listItemIndex", isSelected: false, ), ); this.setState(() { items = newList; }); } onListItemChange(int listItemIndex, bool checked) { final newList = new List<ListItem>.from(items); final currentItem = items[listItemIndex]; newList[listItemIndex] = new ListItem( onChange: currentItem.onChange, isSelected: checked, title: currentItem.title, ); this.setState(() { items = newList; }); } } 列表,而是每次创建一个新列表。

为什么?这是因为,就像我之前解释过的那样,字段应该是不可变的。 items可能是有状态的,但不是不遵循该原则的理由。因此,我们不是编辑列表,而是根据旧列表创建一个新列表。

事实是,如果没有新列表ItemsList会想到&#34;嘿,你发给我的名单和以前一样。所以我不需要刷新吧?&#34;。

现在很酷的是,默认情况下ListView包含有关ItemsList的所有信息。所以ListItem变得非常容易:

getSelectedTitles
相关问题