如何让AnimatedSwitcher切换的两张Card保持相同高度?
解决AnimatedSwitcher卡片翻转动画高度突兀问题
方案1:提前测量并固定最大高度
核心思路是先获取两张卡片的实际高度,取最大值作为容器固定高度,让矮卡片顶部对齐、底部留空,模拟“扩展”效果。
- 定义全局Key用于测量高度
final GlobalKey _card1Key = GlobalKey(); final GlobalKey _card2Key = GlobalKey(); double _maxCardHeight = 0;
- 组件初始化后测量高度
利用WidgetsBinding的帧回调,在组件首次渲染完成后获取两张卡片的高度:
@override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) { // 获取两张卡片的渲染对象 final card1Render = _card1Key.currentContext?.findRenderObject() as RenderBox?; final card2Render = _card2Key.currentContext?.findRenderObject() as RenderBox?; if (card1Render != null && card2Render != null) { setState(() { _maxCardHeight = max(card1Render.size.height, card2Render.size.height); }); } }); }
- 构建布局,固定容器高度
用固定高度的容器包裹AnimatedSwitcher,矮卡片通过Align保持顶部对齐:
Container( height: _maxCardHeight, width: double.infinity, // 保持卡片宽度一致 child: AnimatedSwitcher( duration: const Duration(milliseconds: 500), transitionBuilder: (child, animation) { // 翻转动画实现 final flipTween = Tween(begin: 0.0, end: 1.0).animate(animation); return RotationYTransition(turns: flipTween, child: child); }, child: _showCard1 ? Align( alignment: Alignment.topCenter, child: Card( key: _card1Key, child: Padding( padding: const EdgeInsets.all(16), child: Text("Card one"), ), ), ) : Align( alignment: Alignment.topCenter, child: Card( key: _card2Key, child: Padding( padding: const EdgeInsets.all(16), child: Text("Taller card 2\nwith more text\n" * 5), ), ), ), ), )
方案2:用AnimatedSize实现高度平滑过渡
如果不想提前固定高度,可结合AnimatedSize让容器高度随切换平滑变化,避免突兀跳转:
AnimatedSize( duration: const Duration(milliseconds: 500), // 和翻转动画时长保持一致 child: AnimatedSwitcher( duration: const Duration(milliseconds: 500), transitionBuilder: (child, animation) { final flipTween = Tween(begin: 0.0, end: 1.0).animate(animation); return RotationYTransition(turns: flipTween, child: child); }, child: _showCard1 ? Card( key: const ValueKey(1), child: Padding( padding: const EdgeInsets.all(16), child: Text("Card one"), ), ) : Card( key: const ValueKey(2), child: Padding( padding: const EdgeInsets.all(16), child: Text("Taller card 2\nwith more text\n" * 5), ), ), ), )
注意事项
- 如果卡片文本是动态加载的(比如网络数据),需要在内容更新后重新测量高度;
- 提前测量方案需要确保两张卡片都被渲染过,可初始用
Offstage临时隐藏未显示的卡片,获取高度后再切换; - 两种方案都要保证卡片宽度一致,避免切换时出现宽度跳动。
内容的提问来源于stack exchange,提问作者rococo
相关产品推荐
相关产品推荐

