如何在Flutter中实现底部导航栏的果冻式动画?
Flutter底部导航栏果冻式动画实现方案
要实现你展示的果冻式弹性底部导航栏,核心是利用Flutter的物理动画系统模拟弹簧形变效果,以下是完整的实现示例:
核心实现逻辑
- 使用
SpringSimulation创建符合果冻弹性特性的动画曲线,相比普通曲线更贴近真实的弹性形变 - 为底部导航项绑定点击事件,触发动画重置与播放
- 通过
AnimatedBuilder配合Transform实现图标的缩放/位移动画
完整可运行代码
import 'package:flutter/material.dart'; import 'package:flutter/physics.dart'; class JellyBottomNavBar extends StatefulWidget { const JellyBottomNavBar({super.key}); @override State<JellyBottomNavBar> createState() => _JellyBottomNavBarState(); } class _JellyBottomNavBarState extends State<JellyBottomNavBar> with SingleTickerProviderStateMixin { late AnimationController _animationController; late Animation<double> _jellyAnimation; int _currentTab = 0; @override void initState() { super.initState(); // 初始化动画控制器 _animationController = AnimationController( vsync: this, duration: const Duration(milliseconds: 600), ); // 配置弹簧参数,调节数值可改变果冻弹性 final springSimulation = SpringSimulation( const SpringDescription( mass: 0.4, stiffness: 180, damping: 12, ), 0.0, 1.0, 0.0, ); _jellyAnimation = CurvedAnimation( parent: _animationController, curve: SpringCurve(springSimulation), ); } @override void dispose() { _animationController.dispose(); super.dispose(); } void _switchTab(int index) { if (_currentTab != index) { setState(() => _currentTab = index); // 重置并播放动画 _animationController.reset(); _animationController.forward(); } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('果冻导航栏示例')), body: const Center(child: Text('当前页面内容')), bottomNavigationBar: BottomNavigationBar( currentIndex: _currentTab, selectedItemColor: Colors.blue, unselectedItemColor: Colors.grey, onTap: _switchTab, items: [ _buildNavItem(Icons.home, '首页', 0), _buildNavItem(Icons.search, '搜索', 1), _buildNavItem(Icons.favorite, '收藏', 2), _buildNavItem(Icons.person, '我的', 3), ], ), ); } BottomNavigationBarItem _buildNavItem(IconData icon, String label, int tabIndex) { return BottomNavigationBarItem( icon: AnimatedBuilder( animation: _jellyAnimation, builder: (context, child) { final animationValue = _jellyAnimation.value; // 选中项应用缩放+位移的果冻效果 final scale = _currentTab == tabIndex ? 1.0 + animationValue * 0.25 : 1.0; final translateY = _currentTab == tabIndex ? -animationValue * 6 : 0.0; return Transform( transform: Matrix4.diagonal3Values(scale, scale, 1.0) ..translate(0, translateY), child: child, ); }, child: Icon(icon), ), label: label, ); } } // 自定义弹簧曲线类 class SpringCurve extends Curve { final SpringSimulation simulation; SpringCurve(this.simulation); @override double transform(double t) { return simulation.x(t); } }
参数调节说明
- SpringDescription:
mass:质量越大,动画回弹越慢stiffness:刚度越高,弹性越强damping:阻尼越大,动画衰减越快
- 动画时长:调整
AnimationController的duration可以控制动画的快慢 - 缩放/位移幅度:修改
scale和translateY的乘数,能调整果冻效果的明显程度
内容的提问来源于stack exchange,提问作者SardorbekR
相关产品推荐
相关产品推荐

