Flutter 删除项后ListView.builder中的UI更改
我有一个statefulwidget(容器)列表。这些容器描述课程的参与者 用户可以通过单击按钮删除这些参与者 由于列表是作为流直接从Firestore检索的,因此单击FlatButton并删除时会有一点延迟 在这种情况下,我想禁用该按钮,直到移除该容器。为此,我使用吸收指针包装容器,并使用在设置状态中更改的布尔值编辑吸收参数的值 该问题在更新列表后发生。特定容器的吸收值保持为真。因此,用户不能删除旧的已删除参与者列表中的其他参与者 在参与者列表长度减少后,如何将禁用的值重置为假Flutter 删除项后ListView.builder中的UI更改,flutter,dart,Flutter,Dart,我有一个statefulwidget(容器)列表。这些容器描述课程的参与者 用户可以通过单击按钮删除这些参与者 由于列表是作为流直接从Firestore检索的,因此单击FlatButton并删除时会有一点延迟 在这种情况下,我想禁用该按钮,直到移除该容器。为此,我使用吸收指针包装容器,并使用在设置状态中更改的布尔值编辑吸收参数的值 该问题在更新列表后发生。特定容器的吸收值保持为真。因此,用户不能删除旧的已删除参与者列表中的其他参与者 在参与者列表长度减少后,如何将禁用的值重置为假 class _
class _ParticipantList extends StatelessWidget {
final CourseEventFormBloc courseEventFormBloc;
const _ParticipantList({
Key key,
this.courseEventFormBloc,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return BlocBuilder<CourseEventFormBloc, CourseEventFormState>(
builder: (context, state) {
return Expanded(
child: ListView.builder(
itemCount: state.participants.length,
itemBuilder: (context, index) {
return _ParticipantContainer(
index: index,
courseEventFormBloc: courseEventFormBloc,
);
},
),
);
},
);
}
}
class _ParticipantContainer extends StatefulWidget {
final CourseEventFormBloc courseEventFormBloc;
final int index;
const _ParticipantContainer({
Key key,
@required this.index,
@required this.courseEventFormBloc,
}) : super(key: key);
@override
__ParticipantContainerState createState() => __ParticipantContainerState();
}
class __ParticipantContainerState extends State<_ParticipantContainer> {
bool disabled = false;
@override
Widget build(BuildContext context) {
return BlocBuilder<CourseEventFormBloc, CourseEventFormState>(
builder: (context, state) {
print('${widget.index} - disabled:$disabled');
return AbsorbPointer(
absorbing: disabled,
child: Container(
margin: const EdgeInsets.symmetric(vertical: 4.0),
decoration: BoxDecoration(
color: Colors.blueGrey.shade100,
borderRadius: BorderRadius.all(Radius.circular(13)),
),
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height * 0.07,
alignment: Alignment.center,
child: Stack(
// mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Align(
alignment: Alignment.center,
child: Text(state.participants[widget.index].name),
),
SizedBox(width: 20.0),
Align(
alignment: Alignment.centerLeft,
child: FlatButton(
onPressed: () {
// through this AlertDialog I can delete a participant
// showAlertDialog(context, index, state.participants[index]);
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
//! I might get an error for the Bloc since the Dialog has another context
title: BlocBuilder<CourseEventFormBloc,
CourseEventFormState>(
cubit: widget.courseEventFormBloc,
builder: (context, state) {
return Text(state.participants.isNotEmpty
? state.participants[widget.index].name
: '');
},
),
content:
Text('Möchtest du den Teilnehmer entfernen?'),
actions: <Widget>[
FlatButton(
onPressed: () => Navigator.pop(context),
child: Text(
'nein',
style: TextStyle(color: kDarkRosaColor),
),
),
FlatButton(
onPressed: () {
widget.courseEventFormBloc.add(
CourseEventAdminParticipantDeleted(
widget.index,
state.participants[widget.index],
state.courseEventObject,
),
);
setState(() {
disabled = true;
});
Navigator.pop(context);
},
child: Text(
'ja',
style: TextStyle(color: kDarkRosaColor),
),
),
],
);
});
},
child: Container(
// margin: const EdgeInsets.only(right: 27.0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(100),
border: Border.all(width: 2, color: kDarkRosaColor)),
child: Icon(
Icons.delete,
color: kDarkRosaColor,
),
),
),
),
],
),
),
);
},
);
}
}
为每个列表项生成一个键,以防止框架重用错误的状态 事实上,这正是非全局键的目的:区分在和解过程中无法区分的子项 键可以通过
ValueKey()
从participant
数据库中的任何类似UUID的属性(参与者ID,或简称名称)生成
@覆盖
小部件构建(构建上下文){
返回BlocBuilder(
生成器:(上下文、状态){
扩大回报(
子项:ListView.builder(
itemCount:state.participants.length,
itemBuilder:(上下文,索引){
返回参与者容器(
key:ValueKey(state.participants[index].id),//基于UUID生成ValueKey
index:index,//也许您应该传递整个参与者,而不是索引
courseEventFormBloc:courseEventFormBloc,
);
},
),
);
},
);
}
覆盖
didUpdateWidget
适用于您的特殊情况。但是请记住,如果任何祖先在您的网络请求中触发了重建,那么将调用didUpdateWidget
。因此。AbsorbPointer
可能比您预期的更早被禁用,这是有风险的。为每个列表项生成一个键,以防止框架重用错误的状态
事实上,这正是非全局键的目的:区分在和解过程中无法区分的子项
键可以通过ValueKey()
从participant
数据库中的任何类似UUID的属性(参与者ID,或简称名称)生成
@覆盖
小部件构建(构建上下文){
返回BlocBuilder(
生成器:(上下文、状态){
扩大回报(
子项:ListView.builder(
itemCount:state.participants.length,
itemBuilder:(上下文,索引){
返回参与者容器(
key:ValueKey(state.participants[index].id),//基于UUID生成ValueKey
index:index,//也许您应该传递整个参与者,而不是索引
courseEventFormBloc:courseEventFormBloc,
);
},
),
);
},
);
}
覆盖
didUpdateWidget
适用于您的特殊情况。但是请记住,如果任何祖先在您的网络请求中触发了重建,那么将调用didUpdateWidget
。因此。AbsorbPointer
可能比您预期的更早被禁用,这是有风险的。因为我使用的是Bloc
,最后,我在state类中添加了一个字符串deleteded
。当我删除一个参与者时,我只是将他的uid
传递到新产生的状态
此外,我去掉了有状态的小部件,我正在执行以下检查,以禁止对刚刚删除的参与者进行单击
state.deleteId==state.participants[index].uid,
@First_Strike推荐的方法同样有效,只是他会使用另一个状态管理(有状态的小部件而不是Bloc)。因为我使用的是
Bloc
,最后,我在state类中添加了一个字符串deletedId
。当我删除一个参与者时,我只是将他的uid
传递到新产生的状态
此外,我去掉了有状态的小部件,我正在执行以下检查,以禁止对刚刚删除的参与者进行单击
state.deleteId==state.participants[index].uid,
@First_Strike推荐的方法也有类似的效果,只是他会使用另一个状态管理(有状态的小部件而不是Bloc)。你不能创建一个回调,即当删除完成时。在该回调函数中,您可以使用setState并再次将false指定给禁用的?您不能创建一个回调,即当删除完成时。在该回调函数中,您可以使用setState,然后再次将false指定给禁用的?我更新了答案以演示如何使用键。我更新了答案以演示如何使用键。
@override
void didUpdateWidget(covariant _ParticipantContainer oldWidget) {
super.didUpdateWidget(oldWidget);
disabled = false;
}