Flutter:如何为PreferredSizeWidget(AppBar)添加伸缩与淡入淡出动画?
实现SliverAppBar Bottom的淡入淡出+滑动动画
要解决SliverAppBar底部区域切换生硬的问题,核心是把Bottom区域封装在动画组件中,同时满足PreferredSizeWidget的布局要求,具体实现如下:
1. 初始化动画控制器与动画对象
在页面的State类中创建动画控制器,同时定义控制透明度和偏移量的动画:
late AnimationController _controller; late Animation<double> _opacityAnim; late Animation<double> _offsetAnim; bool _isBottomVisible = false; @override void initState() { super.initState(); _controller = AnimationController( duration: const Duration(milliseconds: 300), vsync: this, ); // 透明度动画:0→1(淡入)/1→0(淡出) _opacityAnim = Tween<double>(begin: 0, end: 1).animate( CurvedAnimation(parent: _controller, curve: Curves.easeInOut), ); // Y轴偏移动画:-20→0(下滑显示)/0→-20(上滑隐藏) _offsetAnim = Tween<double>(begin: -20, end: 0).animate( CurvedAnimation(parent: _controller, curve: Curves.easeOut), ); } @override void dispose() { _controller.dispose(); super.dispose(); }
2. 自定义带动画的Bottom组件
创建继承自PreferredSizeWidget的组件,把动画逻辑封装进去,直接适配SliverAppBar的bottom属性:
class AnimatedBottomBar extends StatelessWidget implements PreferredSizeWidget { final Animation<double> opacityAnim; final Animation<double> offsetAnim; final Widget child; const AnimatedBottomBar({ super.key, required this.opacityAnim, required this.offsetAnim, required this.child, }); @override Size get preferredSize => const Size.fromHeight(48); // 自定义底部栏高度 @override Widget build(BuildContext context) { return SlideTransition( position: Tween<Offset>( begin: Offset(0, offsetAnim.value / preferredSize.height), end: const Offset(0, 0), ).animate(opacityAnim), child: FadeTransition( opacity: opacityAnim, child: child, ), ); } }
3. 绑定SliverAppBar与点击事件
在SliverAppBar中使用自定义动画组件,通过按钮点击触发动画切换:
SliverAppBar( title: const Text("带动画的SliverAppBar"), actions: [ IconButton( icon: Icon(_isBottomVisible ? Icons.expand_less : Icons.expand_more), onPressed: () async { if (_isBottomVisible) { // 执行淡出上移动画 await _controller.reverse(); } else { // 执行淡入下移动画 await _controller.forward(); } setState(() { _isBottomVisible = !_isBottomVisible; }); }, ), ], bottom: _isBottomVisible ? AnimatedBottomBar( opacityAnim: _opacityAnim, offsetAnim: _offsetAnim, child: Container( height: 48, color: Colors.blue[100], alignment: Alignment.center, child: const Text("动画显示的底部区域"), ), ) : null, pinned: true, )
关键说明
- 动画组合:通过
SlideTransition控制上下滑动、FadeTransition控制透明度,完美模拟fadeInDown/fadeOutUp效果 - 布局兼容:自定义组件实现
preferredSize,确保SliverAppBar能正确计算整体高度 - 状态同步:先播放动画再切换显示状态,避免出现生硬的突然切换
内容的提问来源于stack exchange,提问作者Lazizbek Fayziev
相关产品推荐
相关产品推荐

