解决Flutter中‘已移除的Dismissible仍在组件树中’报错问题
问题解决:Dismissible删除后红屏报错
报错A dismissed Dismissible widget is still part of the tree的核心原因是:删除通知后,ListView的数据源未及时更新,导致已被删除的Dismissible组件仍保留在组件树中。以下是针对性的解决方案:
1. 修复状态管理逻辑(推荐用Provider)
将通知数据的读取、删除逻辑统一放到CommonProvider中,确保数据变更能自动通知UI刷新:
class CommonProvider extends ChangeNotifier { List<Notifications>? _notifications; List<Notifications>? get notifications => _notifications; // 初始化加载通知 Future<void> loadNotifications() async { SharedPreferences prefs = await SharedPreferences.getInstance(); String notificationsString = prefs.getString('notifications') ?? '[]'; _notifications = (json.decode(notificationsString) as List) .map((item) => Notifications.fromJson(item)) .toList(); notifyListeners(); // 通知UI更新 } // 删除单条通知 Future<void> deleteNotification(String id) async { SharedPreferences prefs = await SharedPreferences.getInstance(); String notificationsString = prefs.getString('notifications') ?? '[]'; List<Notifications> notificationsList = (json.decode(notificationsString) as List) .map((item) => Notifications.fromJson(item)) .toList(); int indexToDelete = notificationsList.indexWhere((n) => n.id == id); if (indexToDelete != -1) { notificationsList.removeAt(indexToDelete); String updatedString = json.encode(notificationsList); prefs.setString('notifications', updatedString); _notifications = notificationsList; // 更新Provider内的数据源 notifyListeners(); // 触发UI刷新 } } }
2. 修改页面代码,正确绑定状态
移除原FutureBuilder的重复异步请求,改为通过Provider监听数据变化:
class NotificationsPage extends StatefulWidget { const NotificationsPage({super.key}); @override _NotificationsPageState createState() => _NotificationsPageState(); } class _NotificationsPageState extends State<NotificationsPage> { @override void initState() { super.initState(); // 页面初始化时加载通知数据 Provider.of<CommonProvider>(context, listen: false).loadNotifications(); } @override Widget build(BuildContext context) { final cP = Provider.of<CommonProvider>(context); return SafeArea( child: Scaffold( appBar: AppBar(title: const Text('Notifications')), body: Padding( padding: EdgeInsets.symmetric(vertical: 15.h), child: Column( children: [ // 根据Provider状态渲染不同UI if (cP.notifications == null) const Center(child: CircularProgressIndicator()) else if (cP.notifications!.isEmpty) const Center(child: Text('No Notification Available')) else SizedBox( height: 500.h, child: ListView.builder( itemCount: cP.notifications!.length, itemBuilder: (context, index) { final notification = cP.notifications![index]; return Dismissible( key: Key(notification.id.toString()), onDismissed: (direction) { // 调用Provider的删除方法,自动触发UI更新 cP.deleteNotification(notification.id.toString()); }, child: Card( child: ListTile( title: Text(notification.title!), subtitle: Text(notification.subTitle!), leading: CustomImageFrame(icon: notification.icon!), ), ), ); }, ), ), Center( child: InkWell( onTap: () { // 批量删除逻辑同理,需更新Provider数据源并调用notifyListeners }, child: const Icon(Icons.delete), ), ) ], ), ), ), ); } }
3. 临时替代方案(无需修改Provider)
如果暂时不想调整状态管理,可在原deleteNotification方法末尾添加setState强制刷新页面,确保ListView数据源同步更新:
Future<void> deleteNotification(String id) async { // 原删除逻辑不变... if (indexToDelete != -1) { notificationsList.removeAt(indexToDelete); String updatedNotificationsString = json.encode(notificationsList); prefs.setString('notifications', updatedNotificationsString); // 强制刷新页面,更新ListView数据源 if (mounted) setState(() {}); } }
内容的提问来源于stack exchange,提问作者user8
相关产品推荐
相关产品推荐

