gpt4 book ai didi

dart - 读取有状态小部件的状态

转载 作者:IT老高 更新时间:2023-10-28 12:43:38 26 4
gpt4 key购买 nike

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

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

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

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

元素类:

class ListItem extends StatefulWidget {

String _title = "";
bool _isSelected = false;

ListItem(this._title);

@override
State<StatefulWidget> createState() => new ListItemState(_title);
}

class ListItemState extends State<ListItem> {

String _title = "";
bool _isSelected = false;

ListItemState(this._title);

@override
Widget build(BuildContext context) {

return new CheckboxListTile(

title: new Text(_title),
value: _isSelected,
onChanged: (bool value) {
setState(() {
_isSelected = value;
});
},

);

}

String getTitle() {
return _title;
}

bool isSelected() {
return _isSelected;
}

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

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

}

还有列表类:

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();
}

}

最佳答案

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

这意味着 flutter 带有一组限制,迫使您以不同的方式构建您的应用程序:

  • 小部件是不可变的。你不更新它们。您重新创建它们。
  • 您无法访问您 child 的状态。您只能访问 parent 的数据/状态。

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


好的,但是这对我的示例有何改变?

这很简单:这意味着对于一个列表来说,不可能从其中一个列表项中访问信息。

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

所以首先我们需要更改 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
);
}
}

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

此时您可能会想“但是现在那个类(class)不是没有意义吗”?并不真地。在我们的例子中,布局非常简单。但这是创建此类类的好习惯,因为它会拆分布局。为布局逻辑清理父级代码。

不管怎样,让我们​​继续吧。

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

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 可能是有状态的,但这不是不遵循该原则的理由。因此,我们不是编辑列表,而是在旧列表的基础上创建一个新列表。

事实是,如果没有那个 new listListView 会认为“嘿,你给我发了和以前一样的列表。所以我不需要刷新对吧? ”。


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

Iterable<String> getSelectedTitles() {
return items.where((item) => item.isSelected).map((item) => item.title);
}

关于dart - 读取有状态小部件的状态,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50092933/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com