如何在Flutter中为OnBoarding Screen实现指定动画?
Flutter引导页(OnBoarding Screen)实现指定动画方案
根据你提供的动画效果(页面切换时内容渐入+向上位移),系统默认的OnBoarding组件灵活性不足,推荐自定义实现,以下是具体方案:
1. 定义引导页数据模型
先封装每个引导页的内容,方便统一管理:
class OnboardingItem { final String imageAsset; final String title; final String description; OnboardingItem({ required this.imageAsset, required this.title, required this.description, }); }
2. 带动画的单页引导组件
为每个引导页的元素(图片、标题、描述)绑定渐入+位移动画:
class AnimatedOnboardingPage extends StatelessWidget { final OnboardingItem item; final Animation<double> animation; const AnimatedOnboardingPage({ super.key, required this.item, required this.animation, }); @override Widget build(BuildContext context) { // 拆分动画阶段,让元素动画有先后顺序 final fadeAnim = CurvedAnimation( parent: animation, curve: const Interval(0.0, 0.5, curve: Curves.easeOut), ); final slideAnim = CurvedAnimation( parent: animation, curve: const Interval(0.2, 0.7, curve: Curves.easeOutCubic), ); return Column( mainAxisAlignment: MainAxisAlignment.center, children: [ // 图片动画 AnimatedBuilder( animation: animation, builder: (context, child) { return Opacity( opacity: fadeAnim.value, child: Transform.translate( offset: Offset(0, 30 * (1 - slideAnim.value)), child: Image.asset(item.imageAsset, height: 300), ), ); }, ), const SizedBox(height: 40), // 标题动画 AnimatedBuilder( animation: animation, builder: (context, child) { return Opacity( opacity: fadeAnim.value, child: Transform.translate( offset: Offset(0, 20 * (1 - slideAnim.value)), child: Text( item.title, style: const TextStyle(fontSize: 28, fontWeight: FontWeight.bold), ), ), ); }, ), const SizedBox(height: 16), // 描述动画 AnimatedBuilder( animation: animation, builder: (context, child) { return Opacity( opacity: fadeAnim.value, child: Transform.translate( offset: Offset(0, 15 * (1 - slideAnim.value)), child: Padding( padding: const EdgeInsets.symmetric(horizontal: 40), child: Text( item.description, textAlign: TextAlign.center, style: const TextStyle(fontSize: 16, color: Colors.grey), ), ), ), ); }, ), ], ); } }
3. 主引导页容器(PageView+动画控制)
用PageView管理页面切换,配合AnimationController触发页面切换时的动画:
class OnboardingScreen extends StatefulWidget { const OnboardingScreen({super.key}); @override State<OnboardingScreen> createState() => _OnboardingScreenState(); } class _OnboardingScreenState extends State<OnboardingScreen> with SingleTickerProviderStateMixin { late PageController _pageController; late AnimationController _animController; int _currentPage = 0; // 示例引导数据,替换成你自己的内容 final List<OnboardingItem> _pages = [ OnboardingItem( imageAsset: 'assets/onboard1.png', title: '欢迎使用', description: '带你快速了解应用核心功能', ), OnboardingItem( imageAsset: 'assets/onboard2.png', title: '轻松操作', description: '简洁界面,上手零门槛', ), OnboardingItem( imageAsset: 'assets/onboard3.png', title: '开始体验', description: '完成引导,开启你的应用之旅', ), ]; @override void initState() { super.initState(); _pageController = PageController(initialPage: 0); _animController = AnimationController( vsync: this, duration: const Duration(milliseconds: 800), ); // 初始页面自动播放动画 _animController.forward(); } @override void dispose() { _pageController.dispose(); _animController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( body: Column( children: [ Expanded( child: PageView.builder( controller: _pageController, itemCount: _pages.length, onPageChanged: (index) { setState(() => _currentPage = index); // 页面切换时重置并重新播放动画 _animController.reset(); _animController.forward(); }, itemBuilder: (context, index) { return AnimatedOnboardingPage( item: _pages[index], animation: _animController, ); }, ), ), // 页面指示器+操作按钮 Padding( padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 30), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ // 指示器 Row( children: List.generate(_pages.length, (index) { return Container( width: 8, height: 8, margin: const EdgeInsets.symmetric(horizontal: 4), decoration: BoxDecoration( shape: BoxShape.circle, color: _currentPage == index ? Colors.blue : Colors.grey.shade300, ), ); }), ), // 跳转按钮 TextButton( onPressed: () { if (_currentPage == _pages.length - 1) { // 完成引导,跳转到首页 // Navigator.pushReplacement(context, MaterialPageRoute(builder: (_) => HomeScreen())); } else { _pageController.nextPage( duration: const Duration(milliseconds: 300), curve: Curves.easeInOut, ); } }, child: Text( _currentPage == _pages.length - 1 ? '开始' : '下一步', style: const TextStyle(fontSize: 16, color: Colors.blue), ), ), ], ), ), ], ), ); } }
关键说明
- 放弃系统默认
OnBoarding组件,自定义实现可完全控制动画细节 - 通过
AnimationController+CurvedAnimation拆分动画阶段,匹配目标动画的节奏 - 监听
PageView的onPageChanged事件,每次切换页面时重置并触发动画
内容的提问来源于stack exchange,提问作者Karim B.
相关产品推荐
相关产品推荐

