从列表中删除项目后,Flutter Slidable 保持打开状态
Flutter Slidable stays open after item is removed from list
我在 ListView 中使用 Slidable,这样我就可以删除项目。问题是,如果我从列表中删除一个项目,新项目就会滑动打开。这显然不是期望的行为。为了更好地理解,这里有一个Screenvideo。
我的列表是一个动画列表:
` child: AnimatedList(
padding: EdgeInsets.zero,
shrinkWrap: true,
key: listKey,
initialItemCount: widget.month.memories.length,
itemBuilder: (context, index, animation) {
return slideIt(
context,
widget.month.memories[index],
index,
animation,
);
},
),`
这是我的 Slidable:
` Widget slideIt(
BuildContext context,
Memory memory,
int index,
animation,
) {
return SlideTransition(
position: Tween<Offset>(
begin: const Offset(-1, 0),
end: Offset(0, 0),
).animate(
CurvedAnimation(
parent: animation,
curve: Curves.easeIn,
reverseCurve: Curves.easeOut,
),
),
child: Slidable(
actionPane: SlidableDrawerActionPane(),
actionExtentRatio: 0.25,
movementDuration: Duration(milliseconds: 400),
child: Column(
children: [
MemoryTile(
memory: memory,
monthName: widget.month.name,
onTapped: () {
_removeMemoryAtIndex(index, memory);
print('tap on ${memory.description}');
},
),
SizedBox(
height: scaleWidth(20),
),
],
),
secondaryActions: [
SlideAction(
closeOnTap: false,
color: AppColors.secondary,
onTap: () => {
_removeMemoryAtIndex(index, memory),
},
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
CupertinoIcons.trash_fill,
color: AppColors.primary,
size: 30,
),
SizedBox(
height: scaleWidth(5),
),
Text(
'Löschen',
style: AppTextStyles.montserratH6SemiBold,
),
SizedBox(
height: scaleWidth(20),
),
],
),
),
],
),
);
}`
AnimatedList 让它变得有点棘手,所以如果您需要更多信息,请告诉我!我该如何解决这个问题?
您应该为您的滑动件指定一个键。当 Flutter 管理它的状态时,它使用三棵树来做到这一点:小部件树、元素树和渲染对象树。当一个 widget 关闭时,flutter 会尝试通过简单的类型相等将其余 widget 与相应的元素同步。所以,这就是您的应用程序以这种方式运行的原因。 Flutter 取第一个剩余的 widget 加上第一个元素,并比较它们是否具有相同的类型。如果有,Flutter 会使用元素的状态来显示相应的渲染对象。元素树的最后一个元素将被删除。
因此,您需要添加键,Flutter 将另外使用它们以理想的方式同步小部件和元素。
每个 Flutter 小部件都有一个 Key
字段。您应该在创建小部件实例时分配它们。您可以使用一些实用程序 类 来生成这样的键 - 如 ValueKey()、UniqueKey 等。或者,如果数据中有您自己的键,您也可以使用它。
我在 ListView 中使用 Slidable,这样我就可以删除项目。问题是,如果我从列表中删除一个项目,新项目就会滑动打开。这显然不是期望的行为。为了更好地理解,这里有一个Screenvideo。
我的列表是一个动画列表:
` child: AnimatedList(
padding: EdgeInsets.zero,
shrinkWrap: true,
key: listKey,
initialItemCount: widget.month.memories.length,
itemBuilder: (context, index, animation) {
return slideIt(
context,
widget.month.memories[index],
index,
animation,
);
},
),`
这是我的 Slidable:
` Widget slideIt(
BuildContext context,
Memory memory,
int index,
animation,
) {
return SlideTransition(
position: Tween<Offset>(
begin: const Offset(-1, 0),
end: Offset(0, 0),
).animate(
CurvedAnimation(
parent: animation,
curve: Curves.easeIn,
reverseCurve: Curves.easeOut,
),
),
child: Slidable(
actionPane: SlidableDrawerActionPane(),
actionExtentRatio: 0.25,
movementDuration: Duration(milliseconds: 400),
child: Column(
children: [
MemoryTile(
memory: memory,
monthName: widget.month.name,
onTapped: () {
_removeMemoryAtIndex(index, memory);
print('tap on ${memory.description}');
},
),
SizedBox(
height: scaleWidth(20),
),
],
),
secondaryActions: [
SlideAction(
closeOnTap: false,
color: AppColors.secondary,
onTap: () => {
_removeMemoryAtIndex(index, memory),
},
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
CupertinoIcons.trash_fill,
color: AppColors.primary,
size: 30,
),
SizedBox(
height: scaleWidth(5),
),
Text(
'Löschen',
style: AppTextStyles.montserratH6SemiBold,
),
SizedBox(
height: scaleWidth(20),
),
],
),
),
],
),
);
}`
AnimatedList 让它变得有点棘手,所以如果您需要更多信息,请告诉我!我该如何解决这个问题?
您应该为您的滑动件指定一个键。当 Flutter 管理它的状态时,它使用三棵树来做到这一点:小部件树、元素树和渲染对象树。当一个 widget 关闭时,flutter 会尝试通过简单的类型相等将其余 widget 与相应的元素同步。所以,这就是您的应用程序以这种方式运行的原因。 Flutter 取第一个剩余的 widget 加上第一个元素,并比较它们是否具有相同的类型。如果有,Flutter 会使用元素的状态来显示相应的渲染对象。元素树的最后一个元素将被删除。 因此,您需要添加键,Flutter 将另外使用它们以理想的方式同步小部件和元素。
每个 Flutter 小部件都有一个 Key
字段。您应该在创建小部件实例时分配它们。您可以使用一些实用程序 类 来生成这样的键 - 如 ValueKey()、UniqueKey 等。或者,如果数据中有您自己的键,您也可以使用它。