Flutter实现3x3 GridView点击Container触发抖动并保持正方形
Flutter 3x3 GridView 正方形布局+点击抖动实现方案
核心实现思路
分为两个独立模块处理需求,互不耦合:
- 正方形布局:通过GridView内置属性直接控制,无需额外计算
- 点击抖动:给每个网格项单独绑定动画控制器,点击时触发局部动画
1. 正方形GridView配置
直接设置GridView的两个核心参数即可保证所有子项始终为正方形:
crossAxisCount: 3指定3列布局childAspectRatio: 1强制所有子项宽高比为1:1,不管父容器宽度如何变化,子项都会自动适配为正方形
示例代码段:
GridView.count( crossAxisCount: 3, childAspectRatio: 1, padding: const EdgeInsets.all(12), crossAxisSpacing: 8, mainAxisSpacing: 8, children: List.generate(9, (index) => GridItem(index: index)), )
2. 点击抖动动画实现
把每个网格项封装为独立的StatefulWidget,每个组件单独持有动画控制器,避免互相干扰。抖动效果通过Transform.translate配合弹性曲线动画实现小幅偏移即可:
完整的GridItem组件代码:
import 'package:flutter/material.dart'; class GridItem extends StatefulWidget { final int index; const GridItem({super.key, required this.index}); @override State<GridItem> createState() => _GridItemState(); } class _GridItemState extends State<GridItem> with SingleTickerProviderStateMixin { late AnimationController _controller; late Animation<double> _shakeAnimation; @override void initState() { super.initState(); _controller = AnimationController( vsync: this, duration: const Duration(milliseconds: 300), ); // 定义抖动偏移量,范围-4到4像素,可自行调整幅度 _shakeAnimation = Tween<double>(begin: 0, end: 4).animate( CurvedAnimation( parent: _controller, curve: Curves.elasticIn, ), ); // 动画结束后自动重置 _controller.addStatusListener((status) { if (status == AnimationStatus.completed) { _controller.reset(); } }); } @override void dispose() { _controller.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return GestureDetector( onTap: () { _controller.forward(); // 可在此处添加点击后的其他业务逻辑 }, child: AnimatedBuilder( animation: _shakeAnimation, builder: (context, child) { return Transform.translate( offset: Offset(_shakeAnimation.value * (DateTime.now().microsecond % 2 == 0 ? 1 : -1), 0), child: Container( decoration: BoxDecoration( color: Colors.blue[100 * ((widget.index % 9) + 1)], borderRadius: BorderRadius.circular(8), ), child: Center( child: Text('Item ${widget.index + 1}'), ), ), ); }, ), ); } }
效果说明
- 不管窗口/父容器宽度怎么变化,GridView子项始终保持正方形,无需手动计算宽高
- 点击任意子项只会触发当前子项的抖动动画,不会影响其他网格项
- 抖动幅度、时长、抖动方向(可改成上下抖动,修改offset的dy参数即可)都可以自行调整参数修改
内容的提问来源于stack exchange,提问作者Ahmed AL-Dilli
相关产品推荐
相关产品推荐

