Flutter集成flutter_tindercard后删除元素ListView不更新如何解决
问题原因
- 最核心的错误是
element.indexOf(element)的用法错误:你对单个字符串元素调用自身的indexOf方法,返回值永远是0,所以每次只会删除卡片列表的第一个元素,根本删不掉你当前操作的卡片,自然就会出现卡片不消失、底部元素不上移的问题。 - 所有卡片共用同一个
CardController实例,会触发控件的操作冲突。 - 提前把Widget实例存在列表里的写法不合理,Flutter应该靠状态数据驱动UI生成,而不是预存Widget。
修复方案
调整代码逻辑,用索引遍历数据源生成卡片,操作时直接对应当前卡片的索引,同时给每个卡片单独分配控制器,完整可运行代码如下:
import 'package:flutter/material.dart'; import 'package:flutter_tindercard/flutter_tindercard.dart'; class ExampleHomePage extends StatefulWidget { @override _ExampleHomePageState createState() => _ExampleHomePageState(); } class _ExampleHomePageState extends State<ExampleHomePage> with TickerProviderStateMixin { List approved = []; List refused = []; List<String> welcomeImages = [ "https://images.unsplash.com/photo-1631636176993-759dea1a1300?ixid=MnwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHw0fHx8ZW58MHx8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=60", "https://images.unsplash.com/photo-1631634176568-f543af6a41de?ixid=MnwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHw3fHx8ZW58MHx8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=60", "https://images.unsplash.com/photo-1631691971564-adf9419d904e?ixid=MnwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHwxM3x8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=60", "https://images.unsplash.com/photo-1631641906574-24adb8594649?ixid=MnwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHwxMnx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=60", "https://images.unsplash.com/photo-1593642702821-c8da6771f0c6?ixid=MnwxMjA3fDF8MHxlZGl0b3JpYWwtZmVlZHwxMXx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=60", "https://images.unsplash.com/photo-1631621461675-e61a1f28d3d6?ixid=MnwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHw0NHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=60" ]; @override Widget build(BuildContext context) { return Scaffold( body: Container( width: double.infinity, child: ListView( // 直接通过数据源动态生成卡片,不预存Widget children: welcomeImages.asMap().entries.map((entry) { int index = entry.key; String image = entry.value; // 每个卡片单独分配控制器 CardController controller = CardController(); return TinderCarder( image: image, controller: controller, onLeftPress: () { setState(() { // 左滑加入拒绝列表 refused.add(welcomeImages.removeAt(index)); print('拒绝了第$index项,剩余卡片数:${welcomeImages.length}'); }); }, onRightPress: () { setState(() { // 右滑加入通过列表 approved.add(welcomeImages.removeAt(index)); print('通过了第$index项,剩余卡片数:${welcomeImages.length}'); }); }, ); }).toList(), ), ), ); } } class TinderCarder extends StatelessWidget { final String image; Function onLeftPress; Function onRightPress; CardController controller; TinderCarder( {required this.image, required this.controller, required this.onLeftPress, required this.onRightPress}); @override Widget build(BuildContext context) { return Container( height: 200, child: TinderSwapCard( orientation: AmassOrientation.BOTTOM, totalNum: 1, stackNum: 3, swipeEdge: 4.0, maxWidth: double.infinity, maxHeight: MediaQuery.of(context).size.width * 0.9, minWidth: MediaQuery.of(context).size.width * 0.8, minHeight: MediaQuery.of(context).size.width * 0.8, cardBuilder: (context, index) => Card( child: Image.network( image, width: double.infinity, fit: BoxFit.cover, ), ), cardController: controller, swipeUpdateCallback: (DragUpdateDetails details, Alignment align) {}, swipeCompleteCallback: (CardSwipeOrientation orientation, int index) { if (orientation == CardSwipeOrientation.LEFT) { onLeftPress(); } else if (orientation == CardSwipeOrientation.RIGHT) { onRightPress(); } }, ), ); } }
调整说明
- 移除了预存的卡片Widget列表,改为在build方法中通过
welcomeImages数据源动态生成卡片,符合Flutter状态驱动UI的设计逻辑。 - 通过
asMap().entries遍历拿到每个元素的真实索引,操作时直接删除对应下标的数据源元素,调用setState后UI会自动刷新,卡片就会正常移除,底部元素自动上移。 - 每个卡片单独创建
CardController实例,避免操作冲突。 - 补充了通过/拒绝列表的添加逻辑,符合需求。
内容的提问来源于stack exchange,提问作者x-DZ-Ax
相关产品推荐
相关产品推荐

