Flutter中GridView内未声明宽高的容器如何实现按压缩小效果
Flutter 按压按钮缩小效果实现
原有实现示意图:
原有实现的问题
- 主动获取控件尺寸再修改宽度的逻辑会触发布局重算,容易出现首次渲染闪烁、布局偏移问题
- 修改宽度的实现会改变控件的实际占位,和CSS中仅视觉缩小、不影响父布局占位的效果不符
- 依赖帧回调的逻辑耦合性高,在GridView滚动复用场景下容易出现尺寸获取错误
实现思路
不需要主动获取控件尺寸,Flutter的Transform组件可以对控件做视觉上的缩放变换,不会修改控件的实际布局占位,完美适配按钮默认占满父容器空间、仅按压时视觉缩小的需求。
核心逻辑:
- 新增
_scale状态变量控制缩放比例,默认值为1 - 监听按钮的按压、抬起、取消事件动态修改缩放值
- 用
AnimatedContainer实现缩放过程的平滑过渡效果
完整代码
import 'package:flutter/material.dart'; class CircularMenu extends StatefulWidget { List<Widget> children; CircularMenu({Key? key, required this.children}) : super(key: key); @override _CircularMenuState createState() => _CircularMenuState(); } class _CircularMenuState extends State<CircularMenu> { bool _isOpen = false; bool _isAnimating = false; // 缩放控制变量,默认1为原尺寸 double _scale = 1.0; void open() { setState(() { _isOpen = true; }); } void close() { setState(() { _isOpen = false; }); } @override Widget build(BuildContext context) { return Stack( children: [ AnimatedContainer( // 缩放动画时长,可自行调整 duration: const Duration(milliseconds: 100), transform: Matrix4.diagonal3Values(_scale, _scale, 1.0), transformAlignment: Alignment.center, color: Colors.red, child: RawMaterialButton( fillColor: Colors.blue, shape: const CircleBorder(), onPressed: () { if (_isAnimating) return; _isOpen ? close() : open(); }, // 按压时缩放到原尺寸的80% onTapDown: (_) => setState(() => _scale = 0.8), // 抬起后恢复原尺寸 onTapUp: (_) => setState(() => _scale = 1.0), // 滑动取消按压后恢复原尺寸 onTapCancel: () => setState(() => _scale = 1.0), child: const Center(child: Text('HSK')), ), ), ], ); } }
效果说明
- 按钮默认会占满父容器分配的所有空间,不需要手动设置宽高
- 按压时会以控件中心为锚点平滑缩小到原尺寸的80%,和CSS缩放效果完全一致
- 缩放过程仅改变视觉效果,不会影响GridView的布局计算,滚动复用也不会出现异常
内容的提问来源于stack exchange,提问作者João Pedro
相关产品推荐
相关产品推荐

