Flutter实现首次启动应用引导页:组件选择与首次启动检测
嗨,这个问题我刚好有不少实践经验,给你梳理下完整的解决方案:
一、检测应用首次启动状态
要判断是不是首次启动,核心是持久化存储一个标记,下次启动时读取这个标记就能知道用户有没有看过引导页了。Flutter里最常用的轻量存储方案就是shared_preferences,步骤如下:
- 先在
pubspec.yaml里添加依赖:
dependencies: flutter: sdk: flutter shared_preferences: ^2.2.2 # 版本号可以用最新的
- 初始化并读取标记:
我们可以在应用启动时异步读取存储的hasSeenOnboarding字段——如果这个字段不存在或者为false,就说明是首次启动;反之则直接进入主页面。
二、选择合适的Widget实现引导页
首推PageView,它天生适配多页滑动的引导场景,自定义自由度极高。你可以给每个引导页设计不同的布局(比如图片+文字+按钮),最后一页放一个「开始使用」的按钮,点击后更新存储标记并跳转到主页面。
当然如果不想自己从零写,也可以用成熟的第三方库(比如introduction_screen),但原生PageView的优势是完全可控,能贴合你的UI设计。
三、完整代码示例
1. 入口处的判断逻辑
用FutureBuilder来处理异步读取存储的操作,避免阻塞UI:
import 'package:flutter/material.dart'; import 'package:shared_preferences/shared_preferences.dart'; void main() => runApp(const MyApp()); class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( title: '引导页示例', home: FutureBuilder<bool>( future: _checkIfFirstLaunch(), builder: (context, snapshot) { // 等待异步操作完成 if (snapshot.connectionState != ConnectionState.done) { return const Scaffold(body: Center(child: CircularProgressIndicator())); } // 根据结果跳转到引导页或主页 return snapshot.data == false ? const OnboardingScreen() : const HomeScreen(); }, ), ); } // 检查是否首次启动 Future<bool> _checkIfFirstLaunch() async { final prefs = await SharedPreferences.getInstance(); return prefs.getBool('hasSeenOnboarding') ?? false; } }
2. 引导页Widget实现
用PageView做滑动页面,最后一页添加跳转按钮:
class OnboardingScreen extends StatefulWidget { const OnboardingScreen({super.key}); @override State<OnboardingScreen> createState() => _OnboardingScreenState(); } class _OnboardingScreenState extends State<OnboardingScreen> { final PageController _pageController = PageController(); int _currentPage = 0; // 引导页数据 final List<Map<String, String>> _pages = [ { 'title': '欢迎使用', 'description': '这是你的第一个引导页面', 'image': 'assets/onboard1.png' // 替换成你的图片路径 }, { 'title': '功能介绍', 'description': '这里展示应用的核心功能', 'image': 'assets/onboard2.png' }, { 'title': '开始探索', 'description': '点击按钮进入应用', 'image': 'assets/onboard3.png' }, ]; // 标记引导页已查看并跳转到主页 Future<void> _markOnboardingSeen() async { final prefs = await SharedPreferences.getInstance(); await prefs.setBool('hasSeenOnboarding', true); if (mounted) { Navigator.pushReplacement( context, MaterialPageRoute(builder: (context) => const HomeScreen()), ); } } @override Widget build(BuildContext context) { return Scaffold( body: Column( children: [ Expanded( child: PageView.builder( controller: _pageController, itemCount: _pages.length, onPageChanged: (index) { setState(() => _currentPage = index); }, itemBuilder: (context, index) { return Padding( padding: const EdgeInsets.all(32.0), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Image.asset(_pages[index]['image']!), const SizedBox(height: 40), Text( _pages[index]['title']!, style: const TextStyle(fontSize: 24, fontWeight: FontWeight.bold), ), const SizedBox(height: 16), Text( _pages[index]['description']!, textAlign: TextAlign.center, style: const TextStyle(fontSize: 16), ), ], ), ); }, ), ), // 页码指示器 Row( mainAxisAlignment: MainAxisAlignment.center, children: List.generate( _pages.length, (index) => Container( width: 8, height: 8, margin: const EdgeInsets.symmetric(horizontal: 4), decoration: BoxDecoration( shape: BoxShape.circle, color: _currentPage == index ? Colors.blue : Colors.grey, ), ), ), ), const SizedBox(height: 40), // 跳转按钮 _currentPage == _pages.length - 1 ? ElevatedButton( onPressed: _markOnboardingSeen, child: const Text('开始使用'), ) : TextButton( onPressed: () => _pageController.nextPage( duration: const Duration(milliseconds: 300), curve: Curves.easeInOut, ), child: const Text('下一步'), ), const SizedBox(height: 40), ], ), ); } } // 主页示例 class HomeScreen extends StatelessWidget { const HomeScreen({super.key}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('主页')), body: const Center(child: Text('欢迎进入应用!')), ); } }
一些额外提示
- 如果需要重置引导页(比如测试时),可以在设置页添加一个按钮,调用
prefs.remove('hasSeenOnboarding')来清除标记。 - 引导页的动画可以再加一些细节,比如页面切换时的渐入效果,提升用户体验。
- 对于安卓和iOS的沉浸式状态栏,可以在引导页里设置
SystemChrome来适配。
内容的提问来源于stack exchange,提问作者Darkhan
相关产品推荐
相关产品推荐

