调用setState时阻止ExpansionTile重置

时间:2018-04-29 13:42:38

标签: dart flutter

我正在关注官方文档中的示例:https://flutter.io/catalog/samples/expansion-tile-sample/

我添加了一个StreamSubscription,每当Firebase数据库有一个新条目时返回。每次返回时,我都会更新示例中的data并致电setState(){data = newData}

理论上这应该用新值重建整个ListView并且它工作得很好但是,最大的问题是当重建发生时,所有ExpansionTiles都会崩溃到默认状态,如果频繁更新,界面将完全无法使用。 / p>

有没有人知道如何使用官方文档中的示例,但每次都没有使用ExpansionTiles?

1 个答案:

答案 0 :(得分:0)

ExpansionTile状态丢失的原因是重新生成数据后它不再具有相同的密钥。以下是我在documentation code you linked in your question之上运行的实验。我只关注关键部分,即为ExpansionTile分配密钥的位置:

Widget _buildTiles(Entry root) {
  if (root.children.isEmpty) return new ListTile(title: new Text(root.title));
  return new ExpansionTile(
    key: new PageStorageKey<Entry>(root),
    title: new Text(root.title),
    children: root.children.map(_buildTiles).toList(),
  );
}

由于您最有可能使用不可变数据,因此当您从Firebase获取新数据时,您会从中生成新对象。尽管root具有相同的数据且与您相同,但它与Flutter的对象不同。你现在有两种处理方法。一个是覆盖==,我认为这是一个坏主意,并将通过评论解释原因。第二种方法是从您知道相同的数据属性生成密钥(如唯一的数据库密钥)。我为我的例子选择了title属性。

Widget _buildTiles(Entry root) {
  if (root.children.isEmpty) return new ListTile(title: new Text(root.title));
  return new ExpansionTile(
    key: new PageStorageKey<String>(root.title), // root.title == newerRoot.title is true
    title: new Text(root.title),
    children: root.children.map(_buildTiles).toList(),
  );
}

您可以使用this gist中的更新代码自行尝试。我还必须对文档中的原始代码进行一些修改,以便我可以刷新数据并模拟您的情况。