Flutter Grid布局点击单个卡片时所有按钮都被触发如何解决
问题根因
- 你当前把动画控制器
_controller和缩放变量_scale定义在父组件中,所有网格卡片都共用这两个变量,一旦触发动画修改_scale的值,所有绑定了该变量的卡片都会同步执行缩放效果,看起来就像所有卡片的点击事件都被触发了,实际只是所有卡片共享了同一套动画状态。 - 补充小问题:你定义
homeEnabledButtons时要求传入点击回调参数Function fun,但实际调用时没有传入,属于冗余参数,不过和当前bug无关。
修复方案
把单个网格卡片抽成独立的StatefulWidget,每个卡片自己维护自己的动画控制器和缩放状态,点击时只会修改当前卡片的动画参数,不会影响其他卡片。
示例代码:独立卡片组件
class GridCardItem extends StatefulWidget { final int position; const GridCardItem({super.key, required this.position}); @override State<GridCardItem> createState() => _GridCardItemState(); } class _GridCardItemState extends State<GridCardItem> with SingleTickerProviderStateMixin { late AnimationController _controller; late Animation<double> _scale; @override void initState() { super.initState(); _controller = AnimationController( vsync: this, duration: const Duration(milliseconds: 100), ); _scale = Tween<double>(begin: 1.0, end: 0.9).animate(_controller); } @override void dispose() { _controller.dispose(); super.dispose(); } void _buttonHandler() { _controller.forward(); Timer(const Duration(milliseconds: 100), () { _controller.reverse(); }); Timer(const Duration(milliseconds: 50), () { print("当前点击的卡片位置:${widget.position}"); // 此处填写你自己的点击业务逻辑 }); } // 把原来的图标判断逻辑移到这里 IconData _getIconData() { switch(widget.position) { case 0: return Icons.pie_chart; case 1: return Icons.perm_device_info; // 补全其他position对应的图标 default: return Icons.add; } } // 把原来的标题判断逻辑移到这里 String _getTitle() { switch(widget.position) { case 0: return "标题1"; case 1: return "标题2"; // 补全其他position对应的标题 default: return ""; } } @override Widget build(BuildContext context) { return GestureDetector( onTap: _buttonHandler, child: AnimatedBuilder( animation: _scale, builder: (context, child) { return Transform.scale( scale: _scale.value, child: homeEnabledButtons(context, _getTitle(), _getIconData()), ); }, ), ); } // 原homeEnabledButtons方法,可移到此处或者抽为公共工具方法 Widget homeEnabledButtons(BuildContext context, String title, IconData icon) { return Card( elevation: 10.0, // 替换为你自己定义的卡片颜色变量 color: Colors.white, child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( icon, // 替换为你自己定义的主题色变量 color: Colors.blue, size: 100.0, ), Text( title, textAlign: TextAlign.center, // 替换为你自己定义的文本样式 style: Theme.of(context).textTheme.titleSmall, ), ], ), shape: const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(15))), ); } }
GridView部分修改为
GridView( shrinkWrap: true, gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, crossAxisSpacing: 30, mainAxisSpacing: 30, ), children: const [ GridCardItem(position: 0), GridCardItem(position: 1), GridCardItem(position: 2), GridCardItem(position: 3), ], )
内容的提问来源于stack exchange,提问作者Jason Waku
相关产品推荐
相关产品推荐

