如何让Flutter应用的引导页仅在首次安装时显示
实现Flutter引导页仅首次安装显示的方案
要让引导页只在用户首次安装应用时显示,核心是通过本地存储记录引导页的显示状态,这里使用Flutter官方推荐的shared_preferences轻量存储包实现。
步骤1:添加依赖
在项目的pubspec.yaml中添加依赖:
dependencies: flutter: sdk: flutter introduction_screen: ^3.1.1 # 保留你原有的版本 shared_preferences: ^2.2.2 # 新增该依赖
执行flutter pub get完成依赖安装。
步骤2:修改引导页代码
更新IntroScreen,加入状态判断和存储逻辑:
import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:introduction_screen/introduction_screen.dart'; import 'package:shared_preferences/shared_preferences.dart'; // 引入存储包 import 'widget_tree.dart'; class IntroScreen extends StatefulWidget { @override _IntroScreenState createState() => _IntroScreenState(); } class _IntroScreenState extends State<IntroScreen> { final introKey = GlobalKey<IntroductionScreenState>(); late SharedPreferences _prefs; @override void initState() { super.initState(); _initPrefs(); } // 初始化SharedPreferences Future<void> _initPrefs() async { _prefs = await SharedPreferences.getInstance(); } void _onIntroEnd(context) async { // 标记引导页已完成 await _prefs.setBool('hasShownIntro', true); Navigator.of(context).pushReplacement( // 替换路由,避免返回引导页 MaterialPageRoute(builder: (_) => WidgetTree()), ); } Widget _buildFullscreenImage() { return Image.asset( 'assets/images/intro1.png', fit: BoxFit.cover, height: double.infinity, width: double.infinity, alignment: Alignment.center, ); } Widget _buildImage(String assetName, [double width = 350]) { return Image.asset('assets/$assetName', width: width); } @override Widget build(BuildContext context) { const bodyStyle = TextStyle(fontSize: 19.0); const pageDecoration = PageDecoration( titleTextStyle: TextStyle( color: Color.fromARGB(255, 29, 116, 182), fontSize: 30.0, fontWeight: FontWeight.w700, fontFamily: 'assets/fonts/Ubuntu-B.ttf'), bodyTextStyle: bodyStyle, bodyPadding: EdgeInsets.fromLTRB(16.0, 0.0, 16.0, 16.0), pageColor: Color.fromARGB(0, 255, 255, 255), imagePadding: EdgeInsets.zero, ); return IntroductionScreen( key: introKey, globalBackgroundColor: Colors.white, globalHeader: const Align( alignment: Alignment.topRight, child: SafeArea( child: Padding( padding: EdgeInsets.only(top: 16, right: 16), ), ), ), pages: [ PageViewModel( title: '欢迎使用', body: '欢迎来到Mawed,你可以轻松预约诊所,选择适合你的医院和心仪的医生。', image: Image.asset( 'assets/images/intro1.png', width: 400, height: 400, fit: BoxFit.fitWidth, alignment: AlignmentDirectional.bottomCenter, ), decoration: pageDecoration, ), PageViewModel( title: "立即预约", body: "足不出户轻松完成预约,就诊时出示预约凭证即可", image: Image.asset( 'assets/images/intro2.jpg', width: 350, height: 350, fit: BoxFit.fitWidth, alignment: AlignmentDirectional.center, ), decoration: pageDecoration, ), PageViewModel( title: "避免拥挤", body: "告别排队浪费时间,按时就诊更高效", image: Image.asset( 'assets/images/intro3.jpg', width: 350, height: 350, fit: BoxFit.fitWidth, alignment: AlignmentDirectional.center, ), decoration: pageDecoration, ), PageViewModel( title: "选择医院", body: "挑选最适合、离你最近的医院", image: Image.asset( 'assets/images/intro4.jpg', width: 350, height: 350, fit: BoxFit.fitWidth, alignment: AlignmentDirectional.center, ), decoration: pageDecoration, ), PageViewModel( title: "你的症状是?", body: "仔细选择对应的科室或医疗专科", image: Image.asset('assets/images/intro5.png', width: 350, height: 350, fit: BoxFit.fitWidth, alignment: AlignmentDirectional.center), decoration: pageDecoration, ), PageViewModel( title: "了解医生档期", body: "查看医生的可预约时间,选择你方便的时段", image: Image.asset('assets/images/intro6.png', width: 400, height: 400, fit: BoxFit.fitWidth, alignment: AlignmentDirectional.bottomCenter), decoration: pageDecoration, ), ], onDone: () => _onIntroEnd(context), onSkip: () => _onIntroEnd(context), showSkipButton: false, skipOrBackFlex: 0, nextFlex: 0, showBackButton: true, back: const Icon(Icons.arrow_back), skip: const Text('跳过', style: TextStyle(fontWeight: FontWeight.w600)), next: const Icon(Icons.arrow_forward), done: const Text('立即预约', style: TextStyle(fontWeight: FontWeight.w600)), curve: Curves.fastLinearToSlowEaseIn, controlsMargin: const EdgeInsets.all(16), controlsPadding: kIsWeb ? const EdgeInsets.all(12.0) : const EdgeInsets.fromLTRB(8.0, 4.0, 8.0, 4.0), dotsDecorator: const DotsDecorator( size: Size(10.0, 10.0), color: Color(0xFFBDBDBD), activeSize: Size(22.0, 10.0), activeShape: RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(25.0)), ), ), dotsContainerDecorator: const ShapeDecoration( color: Colors.black87, shape: RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(8.0)), ), ), ); } }
步骤3:修改应用入口逻辑
在main.dart中,启动时先检查引导页状态,决定跳转目标:
import 'package:flutter/material.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'intro_screen.dart'; import 'widget_tree.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); // 确保初始化完成 SharedPreferences prefs = await SharedPreferences.getInstance(); bool hasShownIntro = prefs.getBool('hasShownIntro') ?? false; runApp(MyApp(hasShownIntro: hasShownIntro)); } class MyApp extends StatelessWidget { final bool hasShownIntro; const MyApp({super.key, required this.hasShownIntro}); @override Widget build(BuildContext context) { return MaterialApp( title: 'Mawed', theme: ThemeData(primarySwatch: Colors.blue), home: hasShownIntro ? const WidgetTree() : const IntroScreen(), ); } }
关键说明
- 用
SharedPreferences存储布尔值hasShownIntro,默认false代表首次打开应用 - 引导页完成后将
hasShownIntro设为true,后续启动直接进入主页面 - 使用
pushReplacement替换路由,避免用户通过返回键回到引导页
内容的提问来源于stack exchange,提问作者OMER ADIL
相关产品推荐
相关产品推荐

