ListView 传递了一个列表。有必要通过点击从这个 ListView 中删除一个元素。当 ListView builder 的参数没有指定key:或指定时,GlobalKey()那么当 list 元素被删除时,元素的编号飞快,列表在视觉上正确显示,但是如果你尝试编辑某些元素,那么这样的元素会有不正确的数据。例如,如果在 ListView 构建器中指定了某些唯一标识符,key: UniqueKey()则 ListView 元素的行为变得正确且可预测,但在删除任何元素后,列表将自动滚动到最开始,到它的第一个元素。我想从 ListView 中删除一个元素,以便之后它的行为是正确的,并且 ListView 本身不会滚动到最开始。
在这里,我存储了一个列表,我将其传递给 ListView
List<Channel> _editorChannels;
这就是我删除元素的方式。我通过唯一 ID 在列表中查找它并将其删除。
onDelete(Channel c) {
final f = _editorChannels.firstWhere((element) => element.Id == c.Id,
orElse: () => null);
if (f != null) setState(() => _editorChannels.remove(f));
}
这就是 ListView 的样子,它位于 DefaultTabController 选项卡之一中,我将仅简要显示一个选项卡的代码,以免代码过多。
Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(
child: Scaffold(
body: ListView.builder(
key: UniqueKey(),
itemCount: _editorChannels == null
? 0
: _editorChannels.length,
itemBuilder: (context, index) {
final item = _editorChannels[index];
return Card(
shadowColor: Colors.black26,
margin: EdgeInsets.all(3.0),
clipBehavior: Clip.antiAlias,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(2),
),
child: ListTile(
title: Container(
child: Text(
item.Name != null ? item.Name : '',
style: new TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16.0),
)),
subtitle: Text(item.Url),
onTap: () => {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
ChewieDemo(channel: item)),
)
},
isThreeLine: false,
leading: getIconbyId(item.Status),
trailing: PopMenuWidget(
channel: item,
onDelete: () => onDelete(item),
onUpdate: (item) => onUpdate(item),
)),
);
}),
),
)
],
),
使用该参数
key: UniqueKey()会导致每次重绘屏幕时都重新创建小部件。先前创建的小部件视图通过给定的键映射到新的视图,并且该键始终是唯一的。至于GlobalKey,它并没有对将小部件与渲染对象匹配的机制进行任何特殊更改,因为 本质上是对小部件状态的全局引用。在您的示例中,使用UniqueKey会导致 ListView 在其原始状态下完全重新创建,除了保存当前位置的问题外,还会降低性能。
说到性能,使用ListView.builder创建的小部件使用优化来仅呈现列表的可见元素并在滚动时移除远处的元素。第二点,可能在您的情况下导致视图与模型“不匹配”,即当从模型中删除元素时,旧的列表元素不会从视图中删除,而是与新参数一起重用。如果列表元素中没有具有自己状态的元素,那么这不会导致问题。否则,有状态小部件仍将使用其旧状态,尽管通过参数将完全不同的列表元素的数据传递给它。这可以通过一个简单的例子看出:
在行的左侧,使用了无状态小部件,而在右侧,在删除按钮之前,是有状态的。删除行时,下方元素的左右部分不匹配。如果您将列表滚动到末尾并返回,那么不匹配就会消失。有状态的小部件由一个按钮制成,当单击该按钮时,它会根据小部件的参数更新状态。此外,代码中有一个注释掉的片段,它使用UniqueKey作为“拐杖”。