Flutter中ListView.builder内ExpansionTile图标联动问题求助
解决方案
问题核心是所有ExpansionTile共享了同一状态变量,导致动画同步触发。要实现单个项的独立动画,需为每个列表项单独维护展开状态,以下是两种可行方案:
方案一:用StatefulWidget封装独立列表项
将每个ExpansionTile封装为带独立状态的StatefulWidget,让每个项自行管理展开状态与动画:
class CustomExpansionItem extends StatefulWidget { final String title; final Widget content; final String trailingText; const CustomExpansionItem({ super.key, required this.title, required this.content, required this.trailingText, }); @override State<CustomExpansionItem> createState() => _CustomExpansionItemState(); } class _CustomExpansionItemState extends State<CustomExpansionItem> { bool _isExpanded = false; @override Widget build(BuildContext context) { return ExpansionTile( title: Text(widget.title), children: [widget.content], onExpansionChanged: (expanded) { setState(() { _isExpanded = expanded; }); }, trailing: Row( mainAxisSize: MainAxisSize.min, children: [ Text(widget.trailingText), const SizedBox(width: 8), AnimatedRotation( duration: const Duration(milliseconds: 200), turns: _isExpanded ? 0.25 : 0, // 0.25圈对应90度旋转 child: const Icon(Icons.arrow_forward_ios), ), ], ), ); } }
在ListView.builder中直接使用该自定义组件:
ListView.builder( itemCount: 5, itemBuilder: (context, index) { return CustomExpansionItem( title: "标题 $index", content: Padding( padding: const EdgeInsets.all(16), child: Text("内容 $index"), ), trailingText: "更多", ); }, )
方案二:用ValueNotifier+AnimatedBuilder(无需额外StatefulWidget)
若不想创建新的StatefulWidget,可通过ValueNotifier为每个项单独维护状态,配合AnimatedBuilder实现动画:
ListView.builder( itemCount: 5, itemBuilder: (context, index) { final isExpandedNotifier = ValueNotifier(false); return ExpansionTile( title: Text("标题 $index"), children: [ Padding( padding: const EdgeInsets.all(16), child: Text("内容 $index"), ) ], onExpansionChanged: (expanded) { isExpandedNotifier.value = expanded; }, trailing: Row( mainAxisSize: MainAxisSize.min, children: [ const Text("更多"), const SizedBox(width: 8), ValueListenableBuilder( valueListenable: isExpandedNotifier, builder: (context, isExpanded, child) { return AnimatedRotation( duration: const Duration(milliseconds: 200), turns: isExpanded ? 0.25 : 0, child: child, ); }, child: const Icon(Icons.arrow_forward_ios), ), ], ), ); }, )
关键说明
- 两种方案的核心是让每个列表项拥有独立状态变量,避免状态共享导致的同步动画问题
AnimatedRotation的turns参数:0对应0度,0.25对应90度,刚好匹配展开/收起的箭头旋转需求- 保留
Row组件实现文本+图标的组合,解决了最初用Row丢失动画的问题(本质是之前未给每个项绑定独立状态)
内容的提问来源于stack exchange,提问作者doclock4715
相关产品推荐
相关产品推荐

