我一直在用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(...);
答案 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