Flutter_card_swiper卡片滑动时如何重置扩展容器状态?
解决方案:切换卡片时保持容器收缩状态
当前问题源于卡片的展开状态由自身内部管理,切换卡片时无法主动重置状态,导致新卡片出现不必要的展开动画。通过状态提升将展开状态移到父组件管理,即可在卡片切换时主动重置状态,实现“切换后保持收缩,仅用户主动操作才展开”的需求。
步骤1:父组件添加展开状态管理
在_SwipeCardsWidgetState中新增状态映射表,记录每个卡片的展开状态,初始化时全部设为收缩:
class _SwipeCardsWidgetState extends State<SwipeCardsWidget> { final CardSwiperController controller = CardSwiperController(); // 记录每个卡片的展开状态,初始全为收缩 final Map<int, bool> _cardExpansionStates = {}; @override void initState() { super.initState(); // 初始化所有卡片为收缩状态 for (int i = 0; i < candidates.length; i++) { _cardExpansionStates[i] = false; } } // ... 原有代码 }
步骤2:修改卡片切换回调,重置展开状态
在onSwipe和onUndo回调中,将新显示的卡片状态强制重置为收缩:
bool _onSwipe( int previousIndex, int? currentIndex, CardSwiperDirection direction, ) { debugPrint( 'The card $previousIndex was swiped to the ${direction.name}. Now the card $currentIndex is on top', ); // 重置当前显示的卡片为收缩状态 if (currentIndex != null) { setState(() { _cardExpansionStates[currentIndex] = false; }); } return true; } bool _onUndo( int? previousIndex, int currentIndex, CardSwiperDirection direction, ) { debugPrint( 'The card $currentIndex was undod from the ${direction.name}', ); // 重置当前显示的卡片为收缩状态 setState(() { _cardExpansionStates[currentIndex] = false; }); return true; }
步骤3:重构ExampleCard为无状态组件
将ExampleCard改为StatelessWidget,从父组件接收展开状态和状态变更回调:
class ExampleCard extends StatelessWidget { final Person candidate; final bool isExpanded; final void Function(bool) onExpandedChanged; const ExampleCard({ super.key, required this.candidate, required this.isExpanded, required this.onExpandedChanged, }); @override Widget build(BuildContext context) { return GestureDetector( onVerticalDragUpdate: (details) { if (details.delta.dy < 0) { onExpandedChanged(true); } if (details.delta.dy > 0) { onExpandedChanged(false); } }, child: Container( clipBehavior: Clip.hardEdge, decoration: BoxDecoration( borderRadius: const BorderRadius.all(Radius.circular(10)), color: Colors.white, boxShadow: [ BoxShadow( color: Colors.grey.withOpacity(0.2), spreadRadius: 3, blurRadius: 7, offset: const Offset(0, 3), ), ], ), alignment: Alignment.center, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Flexible( child: Container( decoration: BoxDecoration( image: DecorationImage( image: NetworkImage(candidate.imageUrl), fit: BoxFit.cover), gradient: const LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [Color(0xFFD7E9F7), Color(0xFFD7E9F7)], ), ), ), ), AnimatedContainer( duration: const Duration(milliseconds: 300), curve: Curves.easeInOut, height: isExpanded ? MediaQuery.of(context).size.height * 0.30 : MediaQuery.of(context).size.height * 0.15, child: Padding( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Center( child: CustomPaint( painter: MyLinePainter(), size: const Size(40, 3), ), ), Text( '${candidate.name}, ${candidate.age}', style: const TextStyle( color: Colors.black, fontWeight: FontWeight.bold, fontSize: 20, ), ), const SizedBox(height: 5), Text( 'Preferred drink: ${candidate.preferredDrink.name}', style: const TextStyle( color: Colors.grey, fontSize: 15, ), ), const SizedBox(height: 5), Text( 'City: ${candidate.location}', style: const TextStyle(color: Colors.grey), ), const SizedBox(height: 10), if (isExpanded) Expanded( child: Text( 'About me: ${candidate.aboutMe}', style: const TextStyle(color: Colors.grey, fontSize: 15), ), ), ], ), ), ), ], ), ), ); } }
步骤4:修改CardSwiper的卡片构建逻辑
更新cardBuilder,直接基于candidates创建卡片并传递状态和回调:
Flexible( child: CardSwiper( allowedSwipeDirection: const AllowedSwipeDirection.only(left: true, right: true), controller: controller, cardsCount: candidates.length, onSwipe: _onSwipe, onUndo: _onUndo, numberOfCardsDisplayed: 3, backCardOffset: const Offset(40, 40), padding: const EdgeInsets.all(24.0), cardBuilder: ( context, index, horizontalThresholdPercentage, verticalThresholdPercentage, ) => ExampleCard( candidate: candidates[index], isExpanded: _cardExpansionStates[index]!, onExpandedChanged: (value) { setState(() { _cardExpansionStates[index] = value; }); }, ), ), ),
步骤5:清理无用代码
删除_SwipeCardsWidgetState中的final cards = candidates.map(ExampleCard.new).toList();,现在卡片直接在cardBuilder中创建。
内容的提问来源于stack exchange,提问作者Yallz
相关产品推荐
相关产品推荐

