Flutter中如何实现NavigationBar选中图标大小变化的动画(类似BottomNavigationBar)
要实现和BottomNavigationBar一致的选中图标缩放动画,核心是借助Flutter的动画系统,在切换导航项时触发图标缩放的补间动画,以下是具体实现方案:
核心实现逻辑
- 用
AnimationController控制动画时长,搭配Tween定义缩放范围(默认从1.0到1.2再回到1.0,匹配BottomNavigationBar默认效果) - 监听导航项选中事件,触发动画播放
- 用
ScaleTransition包裹导航图标,将动画值绑定到缩放因子上
完整代码示例
import 'package:flutter/material.dart'; void main() => runApp(const MyApp()); class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( home: const NavigationBarAnimationDemo(), ); } } class NavigationBarAnimationDemo extends StatefulWidget { const NavigationBarAnimationDemo({super.key}); @override State<NavigationBarAnimationDemo> createState() => _NavigationBarAnimationDemoState(); } class _NavigationBarAnimationDemoState extends State<NavigationBarAnimationDemo> with SingleTickerProviderStateMixin { int _selectedIndex = 0; late AnimationController _animationController; late Animation<double> _scaleAnimation; @override void initState() { super.initState(); // 初始化动画控制器,时长200ms,和BottomNavigationBar默认一致 _animationController = AnimationController( duration: const Duration(milliseconds: 200), vsync: this, ); // 定义缩放动画:从1.0 -> 1.2 -> 1.0 _scaleAnimation = TweenSequence([ TweenSequenceItem(tween: Tween<double>(begin: 1.0, end: 1.2), weight: 50), TweenSequenceItem(tween: Tween<double>(begin: 1.2, end: 1.0), weight: 50), ]).animate(CurvedAnimation( parent: _animationController, curve: Curves.easeInOut, )); } @override void dispose() { _animationController.dispose(); super.dispose(); } void _onDestinationSelected(int index) { if (index != _selectedIndex) { setState(() { _selectedIndex = index; }); // 重置并播放动画 _animationController.reset(); _animationController.forward(); } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text("NavigationBar 动画演示")), body: const Center(child: Text("当前选中项内容")), bottomNavigationBar: NavigationBar( selectedIndex: _selectedIndex, onDestinationSelected: _onDestinationSelected, destinations: [ _buildNavDestination(Icons.home, "首页"), _buildNavDestination(Icons.search, "搜索"), _buildNavDestination(Icons.person, "我的"), ], ), ); } NavigationDestination _buildNavDestination(IconData icon, String label) { return NavigationDestination( icon: ScaleTransition( scale: _scaleAnimation, child: Icon(icon), ), label: label, ); } }
关键细节说明
- 动画时长设置为200ms,曲线用
Curves.easeInOut,完全匹配BottomNavigationBar的默认动画参数 - 使用
TweenSequence实现先放大再回弹的效果,还原原生组件的动画逻辑 - 每次切换选中项时,先重置动画控制器再执行forward,确保每次切换都能触发完整的缩放动画
- 用
SingleTickerProviderStateMixin提供动画所需的vsync,避免动画在后台运行消耗资源
内容的提问来源于stack exchange,提问作者devblock
相关产品推荐
相关产品推荐

