Flutter中如何基于folding_cell插件实现多折叠卡片?
解决folding_cell插件添加多个折叠卡片的问题
我看你已经尝试用folding_cell插件实现折叠卡片,现在想要添加多个折叠卡片的功能,刚好你已经有了单个卡片和ListView的基础代码,我来帮你完善这两种场景下的实现方案,同时修复一些版本兼容的小问题:
场景1:在容器中添加多个独立折叠卡片
单个折叠卡片用了GlobalKey来控制状态,多个卡片的话需要给每个卡片分配独立的key,我们可以用一个List来管理这些key,这样就能分别控制每个卡片的折叠状态:
class MultiFoldingCellDemo extends StatelessWidget { // 为每个折叠卡片生成独立的GlobalKey final List<GlobalKey<SimpleFoldingCellState>> _cellKeys = List.generate(3, (index) => GlobalKey<SimpleFoldingCellState>()); @override Widget build(BuildContext context) { return Container( color: Color(0xFF2e282a), padding: const EdgeInsets.symmetric(vertical: 10), child: Column( children: List.generate(3, (index) { return Padding( padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 15), child: SimpleFoldingCell( key: _cellKeys[index], frontWidget: _buildFrontWidget(index), innerTopWidget: _buildInnerTopWidget(index), innerBottomWidget: _buildInnerBottomWidget(index), cellSize: Size(MediaQuery.of(context).size.width, 125), padding: EdgeInsets.all(15), animationDuration: Duration(milliseconds: 300), borderRadius: 10, onOpen: () => print('cell $index opened'), onClose: () => print('cell $index closed'), ), ); }), ), ); } Widget _buildFrontWidget(int index) { return Container( color: Color(0xFFffcd3c), alignment: Alignment.center, child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Text("CARD - $index", style: TextStyle( color: Color(0xFF2e282a), fontFamily: 'OpenSans', fontSize: 20.0, fontWeight: FontWeight.w800)), FlatButton( onPressed: () => _cellKeys[index].currentState?.toggleFold(), child: Text("Open"), textColor: Colors.white, color: Colors.indigoAccent, splashColor: Colors.white.withOpacity(0.5), ) ], ), ); } Widget _buildInnerTopWidget(int index) { return Container( color: Color(0xFFff9234), alignment: Alignment.center, child: Text("TITLE - $index", style: TextStyle( color: Color(0xFF2e282a), fontFamily: 'OpenSans', fontSize: 20.0, fontWeight: FontWeight.w800))); } Widget _buildInnerBottomWidget(int index) { return Container( color: Color(0xFFecf2f9), alignment: Alignment.bottomCenter, child: Padding( padding: EdgeInsets.only(bottom: 10), child: FlatButton( onPressed: () => _cellKeys[index].currentState?.toggleFold(), child: Text("Close"), textColor: Colors.white, color: Colors.indigoAccent, splashColor: Colors.white.withOpacity(0.5), ), ), ); } }
场景2:优化ListView中的多折叠卡片实现
你现有的ListView示例已经支持多卡片,但ancestorStateOfType在Flutter 2.12+版本已经被废弃,我帮你替换成最新的findAncestorStateOfType方法,确保代码能正常运行:
class FoldingCellListViewDemo extends StatelessWidget { @override Widget build(BuildContext context) { return Container( color: Color(0xFF2e282a), child: ListView.builder( itemCount: 100, padding: const EdgeInsets.symmetric(vertical: 10), itemBuilder: (context, index) { return Padding( padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 15), child: SimpleFoldingCell( frontWidget: _buildFrontWidget(index), innerTopWidget: _buildInnerTopWidget(index), innerBottomWidget: _buildInnerBottomWidget(index), cellSize: Size(MediaQuery.of(context).size.width, 125), padding: EdgeInsets.all(15), animationDuration: Duration(milliseconds: 300), borderRadius: 10, onOpen: () => print('$index cell opened'), onClose: () => print('$index cell closed')), ); }), ); } Widget _buildFrontWidget(int index) { return Builder( builder: (BuildContext context) { return Container( color: Color(0xFFffcd3c), alignment: Alignment.center, child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Text("CARD - $index", style: TextStyle( color: Color(0xFF2e282a), fontFamily: 'OpenSans', fontSize: 20.0, fontWeight: FontWeight.w800)), FlatButton( onPressed: () { // 替换为Flutter新版本支持的findAncestorStateOfType SimpleFoldingCellState? foldingCellState = context.findAncestorStateOfType<SimpleFoldingCellState>(); foldingCellState?.toggleFold(); }, child: Text("Open"), textColor: Colors.white, color: Colors.indigoAccent, splashColor: Colors.white.withOpacity(0.5), ) ], ), ); }, ); } Widget _buildInnerTopWidget(int index) { return Container( color: Color(0xFFff9234), alignment: Alignment.center, child: Text("TITLE - $index", style: TextStyle( color: Color(0xFF2e282a), fontFamily: 'OpenSans', fontSize: 20.0, fontWeight: FontWeight.w800))); } Widget _buildInnerBottomWidget(int index) { return Builder(builder: (context) { return Container( color: Color(0xFFecf2f9), alignment: Alignment.bottomCenter, child: Padding( padding: EdgeInsets.only(bottom: 10), child: FlatButton( onPressed: () { SimpleFoldingCellState? foldingCellState = context.findAncestorStateOfType<SimpleFoldingCellState>(); foldingCellState?.toggleFold(); }, child: Text("Close"), textColor: Colors.white, color: Colors.indigoAccent, splashColor: Colors.white.withOpacity(0.5), ), ), ); }); } }
几个关键注意点
- 独立状态管理:非列表场景用独立的
GlobalKey列表控制每个卡片;列表场景用Builder包裹卡片内容,结合findAncestorStateOfType获取当前卡片的状态,确保每个卡片的折叠操作互不影响 - 布局适配:给卡片添加适当的内外边距,避免卡片之间过于拥挤,同时确保
cellSize的宽度适配屏幕宽度 - 动态内容扩展:可以根据
index从数据源(比如列表数组)中获取动态内容,替换示例中的静态文本,实现更实用的多卡片效果
内容的提问来源于stack exchange,提问作者raman raman




