You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 20:42:42