📑 目录
📖 概述
本教程将详细介绍如何在 Flutter 应用中集成 intro_slider 三方库,实现一个美观的应用引导页,支持左右滑动查看功能介绍,并提供"跳过"按钮快速进入主界面。
✨ 功能特性
#mermaid-svg-S4WorbQXw6K4OBab{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-S4WorbQXw6K4OBab .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-S4WorbQXw6K4OBab .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-S4WorbQXw6K4OBab .error-icon{fill:#552222;}#mermaid-svg-S4WorbQXw6K4OBab .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-S4WorbQXw6K4OBab .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-S4WorbQXw6K4OBab .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-S4WorbQXw6K4OBab .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-S4WorbQXw6K4OBab .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-S4WorbQXw6K4OBab .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-S4WorbQXw6K4OBab .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-S4WorbQXw6K4OBab .marker{fill:#333333;stroke:#333333;}#mermaid-svg-S4WorbQXw6K4OBab .marker.cross{stroke:#333333;}#mermaid-svg-S4WorbQXw6K4OBab svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-S4WorbQXw6K4OBab p{margin:0;}#mermaid-svg-S4WorbQXw6K4OBab .edge{stroke-width:3;}#mermaid-svg-S4WorbQXw6K4OBab .section–1 rect,#mermaid-svg-S4WorbQXw6K4OBab .section–1 path,#mermaid-svg-S4WorbQXw6K4OBab .section–1 circle,#mermaid-svg-S4WorbQXw6K4OBab .section–1 polygon,#mermaid-svg-S4WorbQXw6K4OBab .section–1 path{fill:hsl(240, 100%, 76.2745098039%);}#mermaid-svg-S4WorbQXw6K4OBab .section–1 text{fill:#ffffff;}#mermaid-svg-S4WorbQXw6K4OBab .node-icon–1{font-size:40px;color:#ffffff;}#mermaid-svg-S4WorbQXw6K4OBab .section-edge–1{stroke:hsl(240, 100%, 76.2745098039%);}#mermaid-svg-S4WorbQXw6K4OBab .edge-depth–1{stroke-width:17;}#mermaid-svg-S4WorbQXw6K4OBab .section–1 line{stroke:hsl(60, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-S4WorbQXw6K4OBab .disabled,#mermaid-svg-S4WorbQXw6K4OBab .disabled circle,#mermaid-svg-S4WorbQXw6K4OBab .disabled text{fill:lightgray;}#mermaid-svg-S4WorbQXw6K4OBab .disabled text{fill:#efefef;}#mermaid-svg-S4WorbQXw6K4OBab .section-0 rect,#mermaid-svg-S4WorbQXw6K4OBab .section-0 path,#mermaid-svg-S4WorbQXw6K4OBab .section-0 circle,#mermaid-svg-S4WorbQXw6K4OBab .section-0 polygon,#mermaid-svg-S4WorbQXw6K4OBab .section-0 path{fill:hsl(60, 100%, 73.5294117647%);}#mermaid-svg-S4WorbQXw6K4OBab .section-0 text{fill:black;}#mermaid-svg-S4WorbQXw6K4OBab .node-icon-0{font-size:40px;color:black;}#mermaid-svg-S4WorbQXw6K4OBab .section-edge-0{stroke:hsl(60, 100%, 73.5294117647%);}#mermaid-svg-S4WorbQXw6K4OBab .edge-depth-0{stroke-width:14;}#mermaid-svg-S4WorbQXw6K4OBab .section-0 line{stroke:hsl(240, 100%, 83.5294117647%);stroke-width:3;}#mermaid-svg-S4WorbQXw6K4OBab .disabled,#mermaid-svg-S4WorbQXw6K4OBab .disabled circle,#mermaid-svg-S4WorbQXw6K4OBab .disabled text{fill:lightgray;}#mermaid-svg-S4WorbQXw6K4OBab .disabled text{fill:#efefef;}#mermaid-svg-S4WorbQXw6K4OBab .section-1 rect,#mermaid-svg-S4WorbQXw6K4OBab .section-1 path,#mermaid-svg-S4WorbQXw6K4OBab .section-1 circle,#mermaid-svg-S4WorbQXw6K4OBab .section-1 polygon,#mermaid-svg-S4WorbQXw6K4OBab .section-1 path{fill:hsl(80, 100%, 76.2745098039%);}#mermaid-svg-S4WorbQXw6K4OBab .section-1 text{fill:black;}#mermaid-svg-S4WorbQXw6K4OBab .node-icon-1{font-size:40px;color:black;}#mermaid-svg-S4WorbQXw6K4OBab .section-edge-1{stroke:hsl(80, 100%, 76.2745098039%);}#mermaid-svg-S4WorbQXw6K4OBab .edge-depth-1{stroke-width:11;}#mermaid-svg-S4WorbQXw6K4OBab .section-1 line{stroke:hsl(260, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-S4WorbQXw6K4OBab .disabled,#mermaid-svg-S4WorbQXw6K4OBab .disabled circle,#mermaid-svg-S4WorbQXw6K4OBab .disabled text{fill:lightgray;}#mermaid-svg-S4WorbQXw6K4OBab .disabled text{fill:#efefef;}#mermaid-svg-S4WorbQXw6K4OBab .section-2 rect,#mermaid-svg-S4WorbQXw6K4OBab .section-2 path,#mermaid-svg-S4WorbQXw6K4OBab .section-2 circle,#mermaid-svg-S4WorbQXw6K4OBab .section-2 polygon,#mermaid-svg-S4WorbQXw6K4OBab .section-2 path{fill:hsl(270, 100%, 76.2745098039%);}#mermaid-svg-S4WorbQXw6K4OBab .section-2 text{fill:#ffffff;}#mermaid-svg-S4WorbQXw6K4OBab .node-icon-2{font-size:40px;color:#ffffff;}#mermaid-svg-S4WorbQXw6K4OBab .section-edge-2{stroke:hsl(270, 100%, 76.2745098039%);}#mermaid-svg-S4WorbQXw6K4OBab .edge-depth-2{stroke-width:8;}#mermaid-svg-S4WorbQXw6K4OBab .section-2 line{stroke:hsl(90, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-S4WorbQXw6K4OBab .disabled,#mermaid-svg-S4WorbQXw6K4OBab .disabled circle,#mermaid-svg-S4WorbQXw6K4OBab .disabled text{fill:lightgray;}#mermaid-svg-S4WorbQXw6K4OBab .disabled text{fill:#efefef;}#mermaid-svg-S4WorbQXw6K4OBab .section-3 rect,#mermaid-svg-S4WorbQXw6K4OBab .section-3 path,#mermaid-svg-S4WorbQXw6K4OBab .section-3 circle,#mermaid-svg-S4WorbQXw6K4OBab .section-3 polygon,#mermaid-svg-S4WorbQXw6K4OBab .section-3 path{fill:hsl(300, 100%, 76.2745098039%);}#mermaid-svg-S4WorbQXw6K4OBab .section-3 text{fill:black;}#mermaid-svg-S4WorbQXw6K4OBab .node-icon-3{font-size:40px;color:black;}#mermaid-svg-S4WorbQXw6K4OBab .section-edge-3{stroke:hsl(300, 100%, 76.2745098039%);}#mermaid-svg-S4WorbQXw6K4OBab .edge-depth-3{stroke-width:5;}#mermaid-svg-S4WorbQXw6K4OBab .section-3 line{stroke:hsl(120, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-S4WorbQXw6K4OBab .disabled,#mermaid-svg-S4WorbQXw6K4OBab .disabled circle,#mermaid-svg-S4WorbQXw6K4OBab .disabled text{fill:lightgray;}#mermaid-svg-S4WorbQXw6K4OBab .disabled text{fill:#efefef;}#mermaid-svg-S4WorbQXw6K4OBab .section-4 rect,#mermaid-svg-S4WorbQXw6K4OBab .section-4 path,#mermaid-svg-S4WorbQXw6K4OBab .section-4 circle,#mermaid-svg-S4WorbQXw6K4OBab .section-4 polygon,#mermaid-svg-S4WorbQXw6K4OBab .section-4 path{fill:hsl(330, 100%, 76.2745098039%);}#mermaid-svg-S4WorbQXw6K4OBab .section-4 text{fill:black;}#mermaid-svg-S4WorbQXw6K4OBab .node-icon-4{font-size:40px;color:black;}#mermaid-svg-S4WorbQXw6K4OBab .section-edge-4{stroke:hsl(330, 100%, 76.2745098039%);}#mermaid-svg-S4WorbQXw6K4OBab .edge-depth-4{stroke-width:2;}#mermaid-svg-S4WorbQXw6K4OBab .section-4 line{stroke:hsl(150, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-S4WorbQXw6K4OBab .disabled,#mermaid-svg-S4WorbQXw6K4OBab .disabled circle,#mermaid-svg-S4WorbQXw6K4OBab .disabled text{fill:lightgray;}#mermaid-svg-S4WorbQXw6K4OBab .disabled text{fill:#efefef;}#mermaid-svg-S4WorbQXw6K4OBab .section-5 rect,#mermaid-svg-S4WorbQXw6K4OBab .section-5 path,#mermaid-svg-S4WorbQXw6K4OBab .section-5 circle,#mermaid-svg-S4WorbQXw6K4OBab .section-5 polygon,#mermaid-svg-S4WorbQXw6K4OBab .section-5 path{fill:hsl(0, 100%, 76.2745098039%);}#mermaid-svg-S4WorbQXw6K4OBab .section-5 text{fill:black;}#mermaid-svg-S4WorbQXw6K4OBab .node-icon-5{font-size:40px;color:black;}#mermaid-svg-S4WorbQXw6K4OBab .section-edge-5{stroke:hsl(0, 100%, 76.2745098039%);}#mermaid-svg-S4WorbQXw6K4OBab .edge-depth-5{stroke-width:-1;}#mermaid-svg-S4WorbQXw6K4OBab .section-5 line{stroke:hsl(180, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-S4WorbQXw6K4OBab .disabled,#mermaid-svg-S4WorbQXw6K4OBab .disabled circle,#mermaid-svg-S4WorbQXw6K4OBab .disabled text{fill:lightgray;}#mermaid-svg-S4WorbQXw6K4OBab .disabled text{fill:#efefef;}#mermaid-svg-S4WorbQXw6K4OBab .section-6 rect,#mermaid-svg-S4WorbQXw6K4OBab .section-6 path,#mermaid-svg-S4WorbQXw6K4OBab .section-6 circle,#mermaid-svg-S4WorbQXw6K4OBab .section-6 polygon,#mermaid-svg-S4WorbQXw6K4OBab .section-6 path{fill:hsl(30, 100%, 76.2745098039%);}#mermaid-svg-S4WorbQXw6K4OBab .section-6 text{fill:black;}#mermaid-svg-S4WorbQXw6K4OBab .node-icon-6{font-size:40px;color:black;}#mermaid-svg-S4WorbQXw6K4OBab .section-edge-6{stroke:hsl(30, 100%, 76.2745098039%);}#mermaid-svg-S4WorbQXw6K4OBab .edge-depth-6{stroke-width:-4;}#mermaid-svg-S4WorbQXw6K4OBab .section-6 line{stroke:hsl(210, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-S4WorbQXw6K4OBab .disabled,#mermaid-svg-S4WorbQXw6K4OBab .disabled circle,#mermaid-svg-S4WorbQXw6K4OBab .disabled text{fill:lightgray;}#mermaid-svg-S4WorbQXw6K4OBab .disabled text{fill:#efefef;}#mermaid-svg-S4WorbQXw6K4OBab .section-7 rect,#mermaid-svg-S4WorbQXw6K4OBab .section-7 path,#mermaid-svg-S4WorbQXw6K4OBab .section-7 circle,#mermaid-svg-S4WorbQXw6K4OBab .section-7 polygon,#mermaid-svg-S4WorbQXw6K4OBab .section-7 path{fill:hsl(90, 100%, 76.2745098039%);}#mermaid-svg-S4WorbQXw6K4OBab .section-7 text{fill:black;}#mermaid-svg-S4WorbQXw6K4OBab .node-icon-7{font-size:40px;color:black;}#mermaid-svg-S4WorbQXw6K4OBab .section-edge-7{stroke:hsl(90, 100%, 76.2745098039%);}#mermaid-svg-S4WorbQXw6K4OBab .edge-depth-7{stroke-width:-7;}#mermaid-svg-S4WorbQXw6K4OBab .section-7 line{stroke:hsl(270, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-S4WorbQXw6K4OBab .disabled,#mermaid-svg-S4WorbQXw6K4OBab .disabled circle,#mermaid-svg-S4WorbQXw6K4OBab .disabled text{fill:lightgray;}#mermaid-svg-S4WorbQXw6K4OBab .disabled text{fill:#efefef;}#mermaid-svg-S4WorbQXw6K4OBab .section-8 rect,#mermaid-svg-S4WorbQXw6K4OBab .section-8 path,#mermaid-svg-S4WorbQXw6K4OBab .section-8 circle,#mermaid-svg-S4WorbQXw6K4OBab .section-8 polygon,#mermaid-svg-S4WorbQXw6K4OBab .section-8 path{fill:hsl(150, 100%, 76.2745098039%);}#mermaid-svg-S4WorbQXw6K4OBab .section-8 text{fill:black;}#mermaid-svg-S4WorbQXw6K4OBab .node-icon-8{font-size:40px;color:black;}#mermaid-svg-S4WorbQXw6K4OBab .section-edge-8{stroke:hsl(150, 100%, 76.2745098039%);}#mermaid-svg-S4WorbQXw6K4OBab .edge-depth-8{stroke-width:-10;}#mermaid-svg-S4WorbQXw6K4OBab .section-8 line{stroke:hsl(330, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-S4WorbQXw6K4OBab .disabled,#mermaid-svg-S4WorbQXw6K4OBab .disabled circle,#mermaid-svg-S4WorbQXw6K4OBab .disabled text{fill:lightgray;}#mermaid-svg-S4WorbQXw6K4OBab .disabled text{fill:#efefef;}#mermaid-svg-S4WorbQXw6K4OBab .section-9 rect,#mermaid-svg-S4WorbQXw6K4OBab .section-9 path,#mermaid-svg-S4WorbQXw6K4OBab .section-9 circle,#mermaid-svg-S4WorbQXw6K4OBab .section-9 polygon,#mermaid-svg-S4WorbQXw6K4OBab .section-9 path{fill:hsl(180, 100%, 76.2745098039%);}#mermaid-svg-S4WorbQXw6K4OBab .section-9 text{fill:black;}#mermaid-svg-S4WorbQXw6K4OBab .node-icon-9{font-size:40px;color:black;}#mermaid-svg-S4WorbQXw6K4OBab .section-edge-9{stroke:hsl(180, 100%, 76.2745098039%);}#mermaid-svg-S4WorbQXw6K4OBab .edge-depth-9{stroke-width:-13;}#mermaid-svg-S4WorbQXw6K4OBab .section-9 line{stroke:hsl(0, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-S4WorbQXw6K4OBab .disabled,#mermaid-svg-S4WorbQXw6K4OBab .disabled circle,#mermaid-svg-S4WorbQXw6K4OBab .disabled text{fill:lightgray;}#mermaid-svg-S4WorbQXw6K4OBab .disabled text{fill:#efefef;}#mermaid-svg-S4WorbQXw6K4OBab .section-10 rect,#mermaid-svg-S4WorbQXw6K4OBab .section-10 path,#mermaid-svg-S4WorbQXw6K4OBab .section-10 circle,#mermaid-svg-S4WorbQXw6K4OBab .section-10 polygon,#mermaid-svg-S4WorbQXw6K4OBab .section-10 path{fill:hsl(210, 100%, 76.2745098039%);}#mermaid-svg-S4WorbQXw6K4OBab .section-10 text{fill:black;}#mermaid-svg-S4WorbQXw6K4OBab .node-icon-10{font-size:40px;color:black;}#mermaid-svg-S4WorbQXw6K4OBab .section-edge-10{stroke:hsl(210, 100%, 76.2745098039%);}#mermaid-svg-S4WorbQXw6K4OBab .edge-depth-10{stroke-width:-16;}#mermaid-svg-S4WorbQXw6K4OBab .section-10 line{stroke:hsl(30, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-S4WorbQXw6K4OBab .disabled,#mermaid-svg-S4WorbQXw6K4OBab .disabled circle,#mermaid-svg-S4WorbQXw6K4OBab .disabled text{fill:lightgray;}#mermaid-svg-S4WorbQXw6K4OBab .disabled text{fill:#efefef;}#mermaid-svg-S4WorbQXw6K4OBab .section-root rect,#mermaid-svg-S4WorbQXw6K4OBab .section-root path,#mermaid-svg-S4WorbQXw6K4OBab .section-root circle,#mermaid-svg-S4WorbQXw6K4OBab .section-root polygon{fill:hsl(240, 100%, 46.2745098039%);}#mermaid-svg-S4WorbQXw6K4OBab .section-root text{fill:#ffffff;}#mermaid-svg-S4WorbQXw6K4OBab .section-root span{color:#ffffff;}#mermaid-svg-S4WorbQXw6K4OBab .section-2 span{color:#ffffff;}#mermaid-svg-S4WorbQXw6K4OBab .icon-container{height:100%;display:flex;justify-content:center;align-items:center;}#mermaid-svg-S4WorbQXw6K4OBab .edge{fill:none;}#mermaid-svg-S4WorbQXw6K4OBab .mindmap-node-label{dy:1em;alignment-baseline:middle;text-anchor:middle;dominant-baseline:middle;text-align:center;}#mermaid-svg-S4WorbQXw6K4OBab :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
引导页功能
页面导航
左右滑动
上一步按钮
下一步按钮
页面指示器
自定义配置
内容自定义
颜色主题
背景图片
按钮样式
用户体验
跳过功能
首次使用检测
平滑动画
状态保存
详细特性:
- ✅ 支持左右滑动查看多个引导页
- 🎨 可自定义每个引导页的内容、颜色、图片
- ⏭️ 提供"跳过"按钮,快速进入主界面
- 🔄 支持"上一步"和"下一步"导航按钮
- 📍 页面指示器显示当前位置
- 💾 首次使用检测,只在首次启动时显示引导页
- 🎯 平滑的页面过渡动画
📋 前置要求
- Flutter SDK 3.9.2 或更高版本
- Dart SDK 3.9.2 或更高版本
- 基本的 Flutter 开发知识
📦 引入三方库步骤
📝 步骤 1:添加依赖
在 pubspec.yaml 文件的 dependencies 部分添加以下依赖:
dependencies:
flutter:
sdk: flutter
# intro_slider: 引导页滑动组件库
intro_slider: ^3.1.0
# shared_preferences: 本地数据存储库,用于保存首次使用标志
shared_preferences: ^2.2.2
📝 代码解读:
- intro_slider: ^3.1.0:引导页滑动组件库,提供左右滑动、页面指示器、导航按钮等功能
- shared_preferences: ^2.2.2:本地键值存储库,用于保存用户是否首次使用应用的标志
💡 版本说明:
- ^3.1.0 表示使用 3.1.0 或更高版本(但低于 4.0.0)
- 使用 ^ 前缀可以自动获取兼容的更新版本
📁 步骤 2:配置资源文件
在 pubspec.yaml 的 flutter 部分添加资源路径(如果还没有添加):
flutter:
uses-material-design: true
assets:
– assets/images/
– assets/animations/
📝 代码解读:
- assets/images/:存放引导页图片资源
- 如果图片路径不存在,组件会显示占位符,不会导致应用崩溃
📂 步骤 3:创建资源文件夹(可选)
在项目根目录创建以下文件夹结构(如果还没有):
项目根目录/
├── assets/
│ ├── images/
│ │ ├── logo.png # 应用 Logo
│ │ ├── intro_1.png # 引导页第1页图片(可选)
│ │ ├── intro_2.png # 引导页第2页图片(可选)
│ │ ├── intro_3.png # 引导页第3页图片(可选)
│ │ └── intro_4.png # 引导页第4页图片(可选)
│ └── animations/ # 动画资源(可选)
💡 提示:
- 图片资源是可选的,如果不提供图片,组件会正常显示文字内容
- 建议图片尺寸:1080×1920 或 750×1334(适配不同屏幕)
- 图片格式:PNG(支持透明)或 JPG
⬇️ 步骤 4:安装依赖
在终端执行以下命令:
flutter pub get
📝 命令说明:
- flutter pub get:下载并安装 pubspec.yaml 中声明的所有依赖包
- 执行成功后,依赖包会被下载到项目的 .dart_tool 目录
✅ 验证安装:
安装成功后,可以在 pubspec.lock 文件中看到依赖包的版本信息。
🎨 具体页面实现功能
1️⃣ 创建首选项管理工具类
创建文件 lib/utils/preferences_helper.dart:
// 导入 shared_preferences 三方库,用于本地数据存储
import 'package:shared_preferences/shared_preferences.dart';
// 导入 Flutter 基础库,用于 debugPrint
import 'package:flutter/foundation.dart';
/// 首选项管理工具类
/// 用于管理应用的本地存储数据,如首次使用标志等
class PreferencesHelper {
/// 首次使用标志的键名
/// 用于在 SharedPreferences 中存储和读取是否首次使用应用的标志
static const String _keyIsFirstLaunch = 'is_first_launch';
/// 检查是否首次启动应用
///
/// 返回值:
/// – true: 首次启动,需要显示引导页
/// – false: 非首次启动,直接进入主页面
static Future<bool> isFirstLaunch() async {
try {
// 获取 SharedPreferences 实例
final prefs = await SharedPreferences.getInstance();
// 读取首次启动标志
// getBool: 获取布尔值,如果键不存在则返回 null
// ?? true: 如果返回 null(即键不存在),则默认为 true(首次启动)
final isFirst = prefs.getBool(_keyIsFirstLaunch) ?? true;
return isFirst;
} catch (e) {
// 如果读取失败,默认返回 true,确保用户能看到引导页
debugPrint('读取首次启动标志失败: $e');
return true;
}
}
/// 设置已非首次启动
///
/// 当用户完成引导页或点击跳过时调用此方法
/// 将首次启动标志设置为 false,下次启动时不再显示引导页
static Future<void> setNotFirstLaunch() async {
try {
final prefs = await SharedPreferences.getInstance();
// 设置首次启动标志为 false
await prefs.setBool(_keyIsFirstLaunch, false);
} catch (e) {
debugPrint('保存首次启动标志失败: $e');
}
}
/// 重置首次启动标志(用于测试或重新显示引导页)
static Future<void> resetFirstLaunch() async {
try {
final prefs = await SharedPreferences.getInstance();
await prefs.setBool(_keyIsFirstLaunch, true);
} catch (e) {
debugPrint('重置首次启动标志失败: $e');
}
}
}
📝 代码解读:
SharedPreferences 是什么?
- Flutter 提供的本地键值存储工具
- 数据会持久化保存在设备上,应用重启后仍然存在
- 适合存储简单的配置信息,如用户偏好设置、首次使用标志等
isFirstLaunch() 方法:
#mermaid-svg-f2nSShXweyRZNBKA{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-f2nSShXweyRZNBKA .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-f2nSShXweyRZNBKA .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-f2nSShXweyRZNBKA .error-icon{fill:#552222;}#mermaid-svg-f2nSShXweyRZNBKA .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-f2nSShXweyRZNBKA .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-f2nSShXweyRZNBKA .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-f2nSShXweyRZNBKA .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-f2nSShXweyRZNBKA .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-f2nSShXweyRZNBKA .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-f2nSShXweyRZNBKA .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-f2nSShXweyRZNBKA .marker{fill:#333333;stroke:#333333;}#mermaid-svg-f2nSShXweyRZNBKA .marker.cross{stroke:#333333;}#mermaid-svg-f2nSShXweyRZNBKA svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-f2nSShXweyRZNBKA p{margin:0;}#mermaid-svg-f2nSShXweyRZNBKA .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-f2nSShXweyRZNBKA .cluster-label text{fill:#333;}#mermaid-svg-f2nSShXweyRZNBKA .cluster-label span{color:#333;}#mermaid-svg-f2nSShXweyRZNBKA .cluster-label span p{background-color:transparent;}#mermaid-svg-f2nSShXweyRZNBKA .label text,#mermaid-svg-f2nSShXweyRZNBKA span{fill:#333;color:#333;}#mermaid-svg-f2nSShXweyRZNBKA .node rect,#mermaid-svg-f2nSShXweyRZNBKA .node circle,#mermaid-svg-f2nSShXweyRZNBKA .node ellipse,#mermaid-svg-f2nSShXweyRZNBKA .node polygon,#mermaid-svg-f2nSShXweyRZNBKA .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-f2nSShXweyRZNBKA .rough-node .label text,#mermaid-svg-f2nSShXweyRZNBKA .node .label text,#mermaid-svg-f2nSShXweyRZNBKA .image-shape .label,#mermaid-svg-f2nSShXweyRZNBKA .icon-shape .label{text-anchor:middle;}#mermaid-svg-f2nSShXweyRZNBKA .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-f2nSShXweyRZNBKA .rough-node .label,#mermaid-svg-f2nSShXweyRZNBKA .node .label,#mermaid-svg-f2nSShXweyRZNBKA .image-shape .label,#mermaid-svg-f2nSShXweyRZNBKA .icon-shape .label{text-align:center;}#mermaid-svg-f2nSShXweyRZNBKA .node.clickable{cursor:pointer;}#mermaid-svg-f2nSShXweyRZNBKA .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-f2nSShXweyRZNBKA .arrowheadPath{fill:#333333;}#mermaid-svg-f2nSShXweyRZNBKA .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-f2nSShXweyRZNBKA .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-f2nSShXweyRZNBKA .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-f2nSShXweyRZNBKA .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-f2nSShXweyRZNBKA .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-f2nSShXweyRZNBKA .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-f2nSShXweyRZNBKA .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-f2nSShXweyRZNBKA .cluster text{fill:#333;}#mermaid-svg-f2nSShXweyRZNBKA .cluster span{color:#333;}#mermaid-svg-f2nSShXweyRZNBKA div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-f2nSShXweyRZNBKA .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-f2nSShXweyRZNBKA rect.text{fill:none;stroke-width:0;}#mermaid-svg-f2nSShXweyRZNBKA .icon-shape,#mermaid-svg-f2nSShXweyRZNBKA .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-f2nSShXweyRZNBKA .icon-shape p,#mermaid-svg-f2nSShXweyRZNBKA .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-f2nSShXweyRZNBKA .icon-shape rect,#mermaid-svg-f2nSShXweyRZNBKA .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-f2nSShXweyRZNBKA .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-f2nSShXweyRZNBKA .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-f2nSShXweyRZNBKA :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
存在
不存在 null
true
false
调用 isFirstLaunch
获取 SharedPreferences 实例
读取键值getBool _keyIsFirstLaunch
键是否存在?
返回存储的布尔值
使用空值合并运算符?? true
返回 true首次启动
返回值
显示引导页
跳过引导页
详细说明:
- getBool(_keyIsFirstLaunch):读取布尔值
- 如果键存在,返回对应的布尔值
- 如果键不存在,返回 null
- ?? true:空值合并运算符
- 如果左侧为 null,返回右侧的值(true)
- 首次安装应用时,键不存在,返回 true(需要显示引导页)
setNotFirstLaunch() 方法:
- setBool(_keyIsFirstLaunch, false):保存布尔值到本地存储
- 调用此方法后,下次启动应用时 isFirstLaunch() 会返回 false
💡 实际应用场景:
#mermaid-svg-5FKoUyVOb4N26Dwt{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-5FKoUyVOb4N26Dwt .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-5FKoUyVOb4N26Dwt .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-5FKoUyVOb4N26Dwt .error-icon{fill:#552222;}#mermaid-svg-5FKoUyVOb4N26Dwt .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-5FKoUyVOb4N26Dwt .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-5FKoUyVOb4N26Dwt .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-5FKoUyVOb4N26Dwt .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-5FKoUyVOb4N26Dwt .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-5FKoUyVOb4N26Dwt .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-5FKoUyVOb4N26Dwt .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-5FKoUyVOb4N26Dwt .marker{fill:#333333;stroke:#333333;}#mermaid-svg-5FKoUyVOb4N26Dwt .marker.cross{stroke:#333333;}#mermaid-svg-5FKoUyVOb4N26Dwt svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-5FKoUyVOb4N26Dwt p{margin:0;}#mermaid-svg-5FKoUyVOb4N26Dwt .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-5FKoUyVOb4N26Dwt .cluster-label text{fill:#333;}#mermaid-svg-5FKoUyVOb4N26Dwt .cluster-label span{color:#333;}#mermaid-svg-5FKoUyVOb4N26Dwt .cluster-label span p{background-color:transparent;}#mermaid-svg-5FKoUyVOb4N26Dwt .label text,#mermaid-svg-5FKoUyVOb4N26Dwt span{fill:#333;color:#333;}#mermaid-svg-5FKoUyVOb4N26Dwt .node rect,#mermaid-svg-5FKoUyVOb4N26Dwt .node circle,#mermaid-svg-5FKoUyVOb4N26Dwt .node ellipse,#mermaid-svg-5FKoUyVOb4N26Dwt .node polygon,#mermaid-svg-5FKoUyVOb4N26Dwt .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-5FKoUyVOb4N26Dwt .rough-node .label text,#mermaid-svg-5FKoUyVOb4N26Dwt .node .label text,#mermaid-svg-5FKoUyVOb4N26Dwt .image-shape .label,#mermaid-svg-5FKoUyVOb4N26Dwt .icon-shape .label{text-anchor:middle;}#mermaid-svg-5FKoUyVOb4N26Dwt .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-5FKoUyVOb4N26Dwt .rough-node .label,#mermaid-svg-5FKoUyVOb4N26Dwt .node .label,#mermaid-svg-5FKoUyVOb4N26Dwt .image-shape .label,#mermaid-svg-5FKoUyVOb4N26Dwt .icon-shape .label{text-align:center;}#mermaid-svg-5FKoUyVOb4N26Dwt .node.clickable{cursor:pointer;}#mermaid-svg-5FKoUyVOb4N26Dwt .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-5FKoUyVOb4N26Dwt .arrowheadPath{fill:#333333;}#mermaid-svg-5FKoUyVOb4N26Dwt .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-5FKoUyVOb4N26Dwt .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-5FKoUyVOb4N26Dwt .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-5FKoUyVOb4N26Dwt .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-5FKoUyVOb4N26Dwt .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-5FKoUyVOb4N26Dwt .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-5FKoUyVOb4N26Dwt .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-5FKoUyVOb4N26Dwt .cluster text{fill:#333;}#mermaid-svg-5FKoUyVOb4N26Dwt .cluster span{color:#333;}#mermaid-svg-5FKoUyVOb4N26Dwt div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-5FKoUyVOb4N26Dwt .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-5FKoUyVOb4N26Dwt rect.text{fill:none;stroke-width:0;}#mermaid-svg-5FKoUyVOb4N26Dwt .icon-shape,#mermaid-svg-5FKoUyVOb4N26Dwt .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-5FKoUyVOb4N26Dwt .icon-shape p,#mermaid-svg-5FKoUyVOb4N26Dwt .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-5FKoUyVOb4N26Dwt .icon-shape rect,#mermaid-svg-5FKoUyVOb4N26Dwt .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-5FKoUyVOb4N26Dwt .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-5FKoUyVOb4N26Dwt .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-5FKoUyVOb4N26Dwt :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
true
false
应用启动
调用 isFirstLaunch
返回结果
显示引导页
显示主页面
用户完成引导
调用 setNotFirstLaunch
保存标志为 false
代码示例:
// 检查是否首次启动
bool isFirst = await PreferencesHelper.isFirstLaunch();
if (isFirst) {
// 显示引导页
Navigator.push(context, MaterialPageRoute(builder: (_) => IntroScreen()));
} else {
// 直接进入主页面
Navigator.push(context, MaterialPageRoute(builder: (_) => HomePage()));
}
// 用户完成引导后,标记已非首次启动
await PreferencesHelper.setNotFirstLaunch();
2️⃣ 创建引导页组件
创建文件 lib/screens/intro_screen.dart:
// 导入 Flutter Material 设计库,提供 UI 组件和主题
import 'package:flutter/material.dart';
// 导入 intro_slider 三方库,用于实现引导页滑动功能
import 'package:intro_slider/intro_slider.dart';
// 导入 intro_slider 的内容配置类
import 'package:intro_slider/slide_object.dart';
// 导入 intro_slider 的配置类
import 'package:intro_slider/scrollbar_behavior_enum.dart';
/// 引导页组件
/// 用于首次启动应用时展示功能介绍
/// 支持左右滑动查看多个引导页,提供"跳过"按钮快速进入主界面
class IntroScreen extends StatefulWidget {
/// 引导页完成后的回调函数
/// 当用户完成引导或点击跳过时调用,用于跳转到主页面
final VoidCallback onDone;
/// 构造函数
const IntroScreen({
super.key,
required this.onDone,
});
State<IntroScreen> createState() => _IntroScreenState();
}
/// 引导页状态类
/// 管理引导页的配置和交互逻辑
class _IntroScreenState extends State<IntroScreen> {
/// 引导页列表
/// 每个 Slide 对象代表一个引导页
List<Slide> slides = [];
/// Widget 初始化方法
void initState() {
super.initState();
// 初始化引导页内容
_initSlides();
}
/// 初始化引导页内容
/// 创建多个引导页,展示天气预报应用的主要功能
void _initSlides() {
slides = [
// 第一页:欢迎页
Slide(
title: "欢迎使用天气预报",
description: "实时掌握天气变化,为您的生活出行提供精准的天气信息",
pathImage: "assets/images/intro_1.png",
backgroundColor: const Color(0xFF64B5F6), // 浅蓝色
titleColor: Colors.white,
descriptionColor: Colors.white,
directionColorBegin: Alignment.topLeft,
directionColorEnd: Alignment.bottomRight,
),
// 第二页:实时天气功能
Slide(
title: "实时天气查询",
description: "获取当前位置的实时天气状况,包括温度、湿度、风速等详细信息",
pathImage: "assets/images/intro_2.png",
backgroundColor: const Color(0xFF42A5F5), // 蓝色
titleColor: Colors.white,
descriptionColor: Colors.white,
directionColorBegin: Alignment.topLeft,
directionColorEnd: Alignment.bottomRight,
),
// 第三页:多城市管理
Slide(
title: "多城市管理",
description: "添加多个城市,快速切换查看不同地区的天气情况,方便出行规划",
pathImage: "assets/images/intro_3.png",
backgroundColor: const Color(0xFF1E88E5), // 深蓝色
titleColor: Colors.white,
descriptionColor: Colors.white,
directionColorBegin: Alignment.topLeft,
directionColorEnd: Alignment.bottomRight,
),
// 第四页:天气预报
Slide(
title: "未来天气预报",
description: "查看未来7天的天气预报,提前了解天气变化趋势,做好出行准备",
pathImage: "assets/images/intro_4.png",
backgroundColor: const Color(0xFF1565C0), // 更深蓝色
titleColor: Colors.white,
descriptionColor: Colors.white,
directionColorBegin: Alignment.topLeft,
directionColorEnd: Alignment.bottomRight,
),
];
}
/// 构建 Widget 树
Widget build(BuildContext context) {
return IntroSlider(
// slides: 引导页列表
slides: slides,
// onDonePress: 完成按钮点击回调
onDonePress: () {
widget.onDone();
},
// onSkipPress: 跳过按钮点击回调
onSkipPress: () {
widget.onDone();
},
// showSkipBtn: 是否显示跳过按钮
showSkipBtn: true,
// 按钮样式配置
skipButtonStyle: ButtonStyle(
backgroundColor: WidgetStateProperty.all(Colors.white.withOpacity(0.3)),
foregroundColor: WidgetStateProperty.all(Colors.white),
padding: WidgetStateProperty.all(
const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
),
shape: WidgetStateProperty.all(
RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
),
),
),
// 页面指示器配置
indicatorConfig: IndicatorConfig(
sizeIndicator: 10,
colorIndicator: Colors.white,
colorActiveIndicator: Colors.white.withOpacity(0.5),
typeIndicatorAnimation: TypeIndicatorAnimation.sizeTransition,
),
// 其他配置
scrollbarBehavior: ScrollbarBehavior.HIDE,
hideStatusBar: false,
backgroundColorAllSlides: Colors.blue,
isShowPrevBtn: true,
isShowNextBtn: true,
isShowDoneBtn: true,
);
}
}

📝 代码解读:
Slide 对象属性:
- title:页面标题文字
- description:页面描述文字
- pathImage:页面背景图片路径(可选)
- backgroundColor:页面背景颜色
- titleColor:标题文字颜色
- descriptionColor:描述文字颜色
- directionColorBegin/End:渐变方向(如果使用渐变背景)
IntroSlider 主要配置:
#mermaid-svg-DmjzsRB583BLtrGL{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-DmjzsRB583BLtrGL .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-DmjzsRB583BLtrGL .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-DmjzsRB583BLtrGL .error-icon{fill:#552222;}#mermaid-svg-DmjzsRB583BLtrGL .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-DmjzsRB583BLtrGL .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-DmjzsRB583BLtrGL .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-DmjzsRB583BLtrGL .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-DmjzsRB583BLtrGL .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-DmjzsRB583BLtrGL .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-DmjzsRB583BLtrGL .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-DmjzsRB583BLtrGL .marker{fill:#333333;stroke:#333333;}#mermaid-svg-DmjzsRB583BLtrGL .marker.cross{stroke:#333333;}#mermaid-svg-DmjzsRB583BLtrGL svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-DmjzsRB583BLtrGL p{margin:0;}#mermaid-svg-DmjzsRB583BLtrGL .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-DmjzsRB583BLtrGL .cluster-label text{fill:#333;}#mermaid-svg-DmjzsRB583BLtrGL .cluster-label span{color:#333;}#mermaid-svg-DmjzsRB583BLtrGL .cluster-label span p{background-color:transparent;}#mermaid-svg-DmjzsRB583BLtrGL .label text,#mermaid-svg-DmjzsRB583BLtrGL span{fill:#333;color:#333;}#mermaid-svg-DmjzsRB583BLtrGL .node rect,#mermaid-svg-DmjzsRB583BLtrGL .node circle,#mermaid-svg-DmjzsRB583BLtrGL .node ellipse,#mermaid-svg-DmjzsRB583BLtrGL .node polygon,#mermaid-svg-DmjzsRB583BLtrGL .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-DmjzsRB583BLtrGL .rough-node .label text,#mermaid-svg-DmjzsRB583BLtrGL .node .label text,#mermaid-svg-DmjzsRB583BLtrGL .image-shape .label,#mermaid-svg-DmjzsRB583BLtrGL .icon-shape .label{text-anchor:middle;}#mermaid-svg-DmjzsRB583BLtrGL .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-DmjzsRB583BLtrGL .rough-node .label,#mermaid-svg-DmjzsRB583BLtrGL .node .label,#mermaid-svg-DmjzsRB583BLtrGL .image-shape .label,#mermaid-svg-DmjzsRB583BLtrGL .icon-shape .label{text-align:center;}#mermaid-svg-DmjzsRB583BLtrGL .node.clickable{cursor:pointer;}#mermaid-svg-DmjzsRB583BLtrGL .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-DmjzsRB583BLtrGL .arrowheadPath{fill:#333333;}#mermaid-svg-DmjzsRB583BLtrGL .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-DmjzsRB583BLtrGL .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-DmjzsRB583BLtrGL .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-DmjzsRB583BLtrGL .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-DmjzsRB583BLtrGL .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-DmjzsRB583BLtrGL .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-DmjzsRB583BLtrGL .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-DmjzsRB583BLtrGL .cluster text{fill:#333;}#mermaid-svg-DmjzsRB583BLtrGL .cluster span{color:#333;}#mermaid-svg-DmjzsRB583BLtrGL div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-DmjzsRB583BLtrGL .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-DmjzsRB583BLtrGL rect.text{fill:none;stroke-width:0;}#mermaid-svg-DmjzsRB583BLtrGL .icon-shape,#mermaid-svg-DmjzsRB583BLtrGL .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-DmjzsRB583BLtrGL .icon-shape p,#mermaid-svg-DmjzsRB583BLtrGL .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-DmjzsRB583BLtrGL .icon-shape rect,#mermaid-svg-DmjzsRB583BLtrGL .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-DmjzsRB583BLtrGL .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-DmjzsRB583BLtrGL .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-DmjzsRB583BLtrGL :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
IntroSlider 组件
slides: 引导页列表
onDonePress: 完成回调
onSkipPress: 跳过回调
showSkipBtn: 显示跳过按钮
indicatorConfig: 指示器配置
按钮显示控制
Slide 1
Slide 2
Slide 3
Slide 4
sizeIndicator: 大小
colorIndicator: 颜色
typeIndicatorAnimation: 动画类型
isShowPrevBtn: 上一步
isShowNextBtn: 下一步
isShowDoneBtn: 完成
配置说明:
- slides:引导页列表
- onDonePress:完成按钮回调(最后一页的"开始使用"按钮)
- onSkipPress:跳过按钮回调(右上角的"跳过"按钮)
- showSkipBtn:是否显示跳过按钮
- indicatorConfig:页面指示器配置(小圆点)
- isShowPrevBtn:是否显示"上一步"按钮
- isShowNextBtn:是否显示"下一步"按钮
- isShowDoneBtn:是否显示"完成"按钮(最后一页)
引导页交互流程:
#mermaid-svg-lwJirc3DTNwOUntQ{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-lwJirc3DTNwOUntQ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-lwJirc3DTNwOUntQ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-lwJirc3DTNwOUntQ .error-icon{fill:#552222;}#mermaid-svg-lwJirc3DTNwOUntQ .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-lwJirc3DTNwOUntQ .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-lwJirc3DTNwOUntQ .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-lwJirc3DTNwOUntQ .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-lwJirc3DTNwOUntQ .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-lwJirc3DTNwOUntQ .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-lwJirc3DTNwOUntQ .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-lwJirc3DTNwOUntQ .marker{fill:#333333;stroke:#333333;}#mermaid-svg-lwJirc3DTNwOUntQ .marker.cross{stroke:#333333;}#mermaid-svg-lwJirc3DTNwOUntQ svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-lwJirc3DTNwOUntQ p{margin:0;}#mermaid-svg-lwJirc3DTNwOUntQ .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-lwJirc3DTNwOUntQ .cluster-label text{fill:#333;}#mermaid-svg-lwJirc3DTNwOUntQ .cluster-label span{color:#333;}#mermaid-svg-lwJirc3DTNwOUntQ .cluster-label span p{background-color:transparent;}#mermaid-svg-lwJirc3DTNwOUntQ .label text,#mermaid-svg-lwJirc3DTNwOUntQ span{fill:#333;color:#333;}#mermaid-svg-lwJirc3DTNwOUntQ .node rect,#mermaid-svg-lwJirc3DTNwOUntQ .node circle,#mermaid-svg-lwJirc3DTNwOUntQ .node ellipse,#mermaid-svg-lwJirc3DTNwOUntQ .node polygon,#mermaid-svg-lwJirc3DTNwOUntQ .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-lwJirc3DTNwOUntQ .rough-node .label text,#mermaid-svg-lwJirc3DTNwOUntQ .node .label text,#mermaid-svg-lwJirc3DTNwOUntQ .image-shape .label,#mermaid-svg-lwJirc3DTNwOUntQ .icon-shape .label{text-anchor:middle;}#mermaid-svg-lwJirc3DTNwOUntQ .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-lwJirc3DTNwOUntQ .rough-node .label,#mermaid-svg-lwJirc3DTNwOUntQ .node .label,#mermaid-svg-lwJirc3DTNwOUntQ .image-shape .label,#mermaid-svg-lwJirc3DTNwOUntQ .icon-shape .label{text-align:center;}#mermaid-svg-lwJirc3DTNwOUntQ .node.clickable{cursor:pointer;}#mermaid-svg-lwJirc3DTNwOUntQ .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-lwJirc3DTNwOUntQ .arrowheadPath{fill:#333333;}#mermaid-svg-lwJirc3DTNwOUntQ .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-lwJirc3DTNwOUntQ .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-lwJirc3DTNwOUntQ .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-lwJirc3DTNwOUntQ .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-lwJirc3DTNwOUntQ .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-lwJirc3DTNwOUntQ .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-lwJirc3DTNwOUntQ .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-lwJirc3DTNwOUntQ .cluster text{fill:#333;}#mermaid-svg-lwJirc3DTNwOUntQ .cluster span{color:#333;}#mermaid-svg-lwJirc3DTNwOUntQ div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-lwJirc3DTNwOUntQ .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-lwJirc3DTNwOUntQ rect.text{fill:none;stroke-width:0;}#mermaid-svg-lwJirc3DTNwOUntQ .icon-shape,#mermaid-svg-lwJirc3DTNwOUntQ .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-lwJirc3DTNwOUntQ .icon-shape p,#mermaid-svg-lwJirc3DTNwOUntQ .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-lwJirc3DTNwOUntQ .icon-shape rect,#mermaid-svg-lwJirc3DTNwOUntQ .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-lwJirc3DTNwOUntQ .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-lwJirc3DTNwOUntQ .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-lwJirc3DTNwOUntQ :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
点击跳过
滑动到最后一页
点击上一步
点击下一步
用户进入引导页
用户操作
触发 onSkipPress
显示完成按钮
返回上一页
进入下一页
点击开始使用
触发 onDonePress
调用回调函数
保存首次使用标志
跳转到主页面
💡 自定义按钮样式:
// 自定义跳过按钮
renderSkipBtn: () {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.3),
borderRadius: BorderRadius.circular(20),
),
child: const Text(
"跳过",
style: TextStyle(
color: Colors.white,
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
);
},
3️⃣ 修改主应用入口
修改文件 lib/main.dart:
// 导入必要的库
import 'package:flutter/material.dart';
import 'package:flutter_splash_screen/flutter_splash_screen.dart';
import 'screens/splash_screen.dart';
import 'screens/intro_screen.dart';
import 'utils/preferences_helper.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
Widget build(BuildContext context) {
return MaterialApp(
title: '天气预报',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
useMaterial3: true,
),
home: const SplashWrapper(),
debugShowCheckedModeBanner: false,
);
}
}
/// 启动页包装器 Widget
/// 负责显示启动页、引导页和主页面的跳转逻辑
class SplashWrapper extends StatefulWidget {
const SplashWrapper({super.key});
State<SplashWrapper> createState() => _SplashWrapperState();
}
/// 启动页包装器的状态类
class _SplashWrapperState extends State<SplashWrapper> {
/// 页面显示状态枚举
enum PageState {
splash, // 显示启动页
intro, // 显示引导页(首次使用)
home, // 显示主页面
}
PageState _pageState = PageState.splash;
void initState() {
super.initState();
_hideNativeSplash();
}
/// 隐藏原生启动屏
Future<void> _hideNativeSplash() async {
await Future.delayed(const Duration(milliseconds: 100));
if (mounted) {
await FlutterSplashScreen.hide();
}
}
/// 启动页完成回调函数
/// 检查是否首次使用,决定显示引导页还是主页面
void _onSplashComplete() async {
if (!mounted) return;
// 检查是否首次启动应用
final isFirst = await PreferencesHelper.isFirstLaunch();
if (mounted) {
setState(() {
if (isFirst) {
// 首次启动,显示引导页
_pageState = PageState.intro;
} else {
// 非首次启动,直接显示主页面
_pageState = PageState.home;
}
});
}
}
/// 引导页完成回调函数
/// 标记已非首次启动,并跳转到主页面
void _onIntroComplete() async {
// 标记已非首次启动
await PreferencesHelper.setNotFirstLaunch();
if (mounted) {
setState(() {
_pageState = PageState.home;
});
}
}
/// 构建 Widget 树
Widget build(BuildContext context) {
switch (_pageState) {
case PageState.splash:
// 显示启动页
return SplashScreen(
duration: 2000,
enableAnimation: true,
logoPath: 'assets/images/logo.png',
onComplete: _onSplashComplete,
);
case PageState.intro:
// 显示引导页(首次使用)
return IntroScreen(
onDone: _onIntroComplete,
);
case PageState.home:
// 显示主页面
return const MyHomePage(title: '天气预报');
}
}
}
📝 代码解读:
页面流程:
主页面
引导页
PreferencesHelper
启动页
应用启动
主页面
引导页
PreferencesHelper
启动页
应用启动
#mermaid-svg-O1cPZOp9Fp2JKbA1{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-O1cPZOp9Fp2JKbA1 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-O1cPZOp9Fp2JKbA1 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-O1cPZOp9Fp2JKbA1 .error-icon{fill:#552222;}#mermaid-svg-O1cPZOp9Fp2JKbA1 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-O1cPZOp9Fp2JKbA1 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-O1cPZOp9Fp2JKbA1 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-O1cPZOp9Fp2JKbA1 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-O1cPZOp9Fp2JKbA1 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-O1cPZOp9Fp2JKbA1 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-O1cPZOp9Fp2JKbA1 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-O1cPZOp9Fp2JKbA1 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-O1cPZOp9Fp2JKbA1 .marker.cross{stroke:#333333;}#mermaid-svg-O1cPZOp9Fp2JKbA1 svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-O1cPZOp9Fp2JKbA1 p{margin:0;}#mermaid-svg-O1cPZOp9Fp2JKbA1 .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-O1cPZOp9Fp2JKbA1 text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-O1cPZOp9Fp2JKbA1 .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-O1cPZOp9Fp2JKbA1 .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-O1cPZOp9Fp2JKbA1 .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-O1cPZOp9Fp2JKbA1 .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-O1cPZOp9Fp2JKbA1 #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-O1cPZOp9Fp2JKbA1 .sequenceNumber{fill:white;}#mermaid-svg-O1cPZOp9Fp2JKbA1 #sequencenumber{fill:#333;}#mermaid-svg-O1cPZOp9Fp2JKbA1 #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-O1cPZOp9Fp2JKbA1 .messageText{fill:#333;stroke:none;}#mermaid-svg-O1cPZOp9Fp2JKbA1 .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-O1cPZOp9Fp2JKbA1 .labelText,#mermaid-svg-O1cPZOp9Fp2JKbA1 .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-O1cPZOp9Fp2JKbA1 .loopText,#mermaid-svg-O1cPZOp9Fp2JKbA1 .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-O1cPZOp9Fp2JKbA1 .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-O1cPZOp9Fp2JKbA1 .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-O1cPZOp9Fp2JKbA1 .noteText,#mermaid-svg-O1cPZOp9Fp2JKbA1 .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-O1cPZOp9Fp2JKbA1 .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-O1cPZOp9Fp2JKbA1 .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-O1cPZOp9Fp2JKbA1 .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-O1cPZOp9Fp2JKbA1 .actorPopupMenu{position:absolute;}#mermaid-svg-O1cPZOp9Fp2JKbA1 .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-O1cPZOp9Fp2JKbA1 .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-O1cPZOp9Fp2JKbA1 .actor-man circle,#mermaid-svg-O1cPZOp9Fp2JKbA1 line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-O1cPZOp9Fp2JKbA1 :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
alt
[首次使用 (true)]
[非首次使用 (false)]
显示启动页
持续2秒
检查是否首次使用
isFirstLaunch()
返回结果
显示引导页
用户滑动/操作
保存标志
setNotFirstLaunch()
跳转到主页面
直接显示主页面
详细步骤:
状态管理:
#mermaid-svg-RZGGdoemE7iZBpGh{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-RZGGdoemE7iZBpGh .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-RZGGdoemE7iZBpGh .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-RZGGdoemE7iZBpGh .error-icon{fill:#552222;}#mermaid-svg-RZGGdoemE7iZBpGh .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-RZGGdoemE7iZBpGh .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-RZGGdoemE7iZBpGh .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-RZGGdoemE7iZBpGh .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-RZGGdoemE7iZBpGh .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-RZGGdoemE7iZBpGh .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-RZGGdoemE7iZBpGh .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-RZGGdoemE7iZBpGh .marker{fill:#333333;stroke:#333333;}#mermaid-svg-RZGGdoemE7iZBpGh .marker.cross{stroke:#333333;}#mermaid-svg-RZGGdoemE7iZBpGh svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-RZGGdoemE7iZBpGh p{margin:0;}#mermaid-svg-RZGGdoemE7iZBpGh defs #statediagram-barbEnd{fill:#333333;stroke:#333333;}#mermaid-svg-RZGGdoemE7iZBpGh g.stateGroup text{fill:#9370DB;stroke:none;font-size:10px;}#mermaid-svg-RZGGdoemE7iZBpGh g.stateGroup text{fill:#333;stroke:none;font-size:10px;}#mermaid-svg-RZGGdoemE7iZBpGh g.stateGroup .state-title{font-weight:bolder;fill:#131300;}#mermaid-svg-RZGGdoemE7iZBpGh g.stateGroup rect{fill:#ECECFF;stroke:#9370DB;}#mermaid-svg-RZGGdoemE7iZBpGh g.stateGroup line{stroke:#333333;stroke-width:1;}#mermaid-svg-RZGGdoemE7iZBpGh .transition{stroke:#333333;stroke-width:1;fill:none;}#mermaid-svg-RZGGdoemE7iZBpGh .stateGroup .composit{fill:white;border-bottom:1px;}#mermaid-svg-RZGGdoemE7iZBpGh .stateGroup .alt-composit{fill:#e0e0e0;border-bottom:1px;}#mermaid-svg-RZGGdoemE7iZBpGh .state-note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-RZGGdoemE7iZBpGh .state-note text{fill:black;stroke:none;font-size:10px;}#mermaid-svg-RZGGdoemE7iZBpGh .stateLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5;}#mermaid-svg-RZGGdoemE7iZBpGh .edgeLabel .label rect{fill:#ECECFF;opacity:0.5;}#mermaid-svg-RZGGdoemE7iZBpGh .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-RZGGdoemE7iZBpGh .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-RZGGdoemE7iZBpGh .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-RZGGdoemE7iZBpGh .edgeLabel .label text{fill:#333;}#mermaid-svg-RZGGdoemE7iZBpGh .label div .edgeLabel{color:#333;}#mermaid-svg-RZGGdoemE7iZBpGh .stateLabel text{fill:#131300;font-size:10px;font-weight:bold;}#mermaid-svg-RZGGdoemE7iZBpGh .node circle.state-start{fill:#333333;stroke:#333333;}#mermaid-svg-RZGGdoemE7iZBpGh .node .fork-join{fill:#333333;stroke:#333333;}#mermaid-svg-RZGGdoemE7iZBpGh .node circle.state-end{fill:#9370DB;stroke:white;stroke-width:1.5;}#mermaid-svg-RZGGdoemE7iZBpGh .end-state-inner{fill:white;stroke-width:1.5;}#mermaid-svg-RZGGdoemE7iZBpGh .node rect{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-RZGGdoemE7iZBpGh .node polygon{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-RZGGdoemE7iZBpGh #statediagram-barbEnd{fill:#333333;}#mermaid-svg-RZGGdoemE7iZBpGh .statediagram-cluster rect{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-RZGGdoemE7iZBpGh .cluster-label,#mermaid-svg-RZGGdoemE7iZBpGh .nodeLabel{color:#131300;}#mermaid-svg-RZGGdoemE7iZBpGh .statediagram-cluster rect.outer{rx:5px;ry:5px;}#mermaid-svg-RZGGdoemE7iZBpGh .statediagram-state .divider{stroke:#9370DB;}#mermaid-svg-RZGGdoemE7iZBpGh .statediagram-state .title-state{rx:5px;ry:5px;}#mermaid-svg-RZGGdoemE7iZBpGh .statediagram-cluster.statediagram-cluster .inner{fill:white;}#mermaid-svg-RZGGdoemE7iZBpGh .statediagram-cluster.statediagram-cluster-alt .inner{fill:#f0f0f0;}#mermaid-svg-RZGGdoemE7iZBpGh .statediagram-cluster .inner{rx:0;ry:0;}#mermaid-svg-RZGGdoemE7iZBpGh .statediagram-state rect.basic{rx:5px;ry:5px;}#mermaid-svg-RZGGdoemE7iZBpGh .statediagram-state rect.divider{stroke-dasharray:10,10;fill:#f0f0f0;}#mermaid-svg-RZGGdoemE7iZBpGh .note-edge{stroke-dasharray:5;}#mermaid-svg-RZGGdoemE7iZBpGh .statediagram-note rect{fill:#fff5ad;stroke:#aaaa33;stroke-width:1px;rx:0;ry:0;}#mermaid-svg-RZGGdoemE7iZBpGh .statediagram-note rect{fill:#fff5ad;stroke:#aaaa33;stroke-width:1px;rx:0;ry:0;}#mermaid-svg-RZGGdoemE7iZBpGh .statediagram-note text{fill:black;}#mermaid-svg-RZGGdoemE7iZBpGh .statediagram-note .nodeLabel{color:black;}#mermaid-svg-RZGGdoemE7iZBpGh .statediagram .edgeLabel{color:red;}#mermaid-svg-RZGGdoemE7iZBpGh #dependencyStart,#mermaid-svg-RZGGdoemE7iZBpGh #dependencyEnd{fill:#333333;stroke:#333333;stroke-width:1;}#mermaid-svg-RZGGdoemE7iZBpGh .statediagramTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-RZGGdoemE7iZBpGh :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
应用启动
首次使用isFirstLaunch = true
非首次使用isFirstLaunch = false
完成引导setNotFirstLaunch
应用退出
Splash
Intro
Home
显示启动页持续2秒
显示引导页用户可滑动查看可点击跳过
显示主页面正常使用应用
状态切换机制:
- 使用 PageState 枚举管理页面状态
- 通过 setState() 切换页面状态
- 使用 mounted 检查确保 Widget 仍然存在
💡 流程说明:
#mermaid-svg-usTiZ44TfMKZIp78{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-usTiZ44TfMKZIp78 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-usTiZ44TfMKZIp78 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-usTiZ44TfMKZIp78 .error-icon{fill:#552222;}#mermaid-svg-usTiZ44TfMKZIp78 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-usTiZ44TfMKZIp78 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-usTiZ44TfMKZIp78 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-usTiZ44TfMKZIp78 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-usTiZ44TfMKZIp78 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-usTiZ44TfMKZIp78 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-usTiZ44TfMKZIp78 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-usTiZ44TfMKZIp78 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-usTiZ44TfMKZIp78 .marker.cross{stroke:#333333;}#mermaid-svg-usTiZ44TfMKZIp78 svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-usTiZ44TfMKZIp78 p{margin:0;}#mermaid-svg-usTiZ44TfMKZIp78 .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-usTiZ44TfMKZIp78 .cluster-label text{fill:#333;}#mermaid-svg-usTiZ44TfMKZIp78 .cluster-label span{color:#333;}#mermaid-svg-usTiZ44TfMKZIp78 .cluster-label span p{background-color:transparent;}#mermaid-svg-usTiZ44TfMKZIp78 .label text,#mermaid-svg-usTiZ44TfMKZIp78 span{fill:#333;color:#333;}#mermaid-svg-usTiZ44TfMKZIp78 .node rect,#mermaid-svg-usTiZ44TfMKZIp78 .node circle,#mermaid-svg-usTiZ44TfMKZIp78 .node ellipse,#mermaid-svg-usTiZ44TfMKZIp78 .node polygon,#mermaid-svg-usTiZ44TfMKZIp78 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-usTiZ44TfMKZIp78 .rough-node .label text,#mermaid-svg-usTiZ44TfMKZIp78 .node .label text,#mermaid-svg-usTiZ44TfMKZIp78 .image-shape .label,#mermaid-svg-usTiZ44TfMKZIp78 .icon-shape .label{text-anchor:middle;}#mermaid-svg-usTiZ44TfMKZIp78 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-usTiZ44TfMKZIp78 .rough-node .label,#mermaid-svg-usTiZ44TfMKZIp78 .node .label,#mermaid-svg-usTiZ44TfMKZIp78 .image-shape .label,#mermaid-svg-usTiZ44TfMKZIp78 .icon-shape .label{text-align:center;}#mermaid-svg-usTiZ44TfMKZIp78 .node.clickable{cursor:pointer;}#mermaid-svg-usTiZ44TfMKZIp78 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-usTiZ44TfMKZIp78 .arrowheadPath{fill:#333333;}#mermaid-svg-usTiZ44TfMKZIp78 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-usTiZ44TfMKZIp78 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-usTiZ44TfMKZIp78 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-usTiZ44TfMKZIp78 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-usTiZ44TfMKZIp78 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-usTiZ44TfMKZIp78 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-usTiZ44TfMKZIp78 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-usTiZ44TfMKZIp78 .cluster text{fill:#333;}#mermaid-svg-usTiZ44TfMKZIp78 .cluster span{color:#333;}#mermaid-svg-usTiZ44TfMKZIp78 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-usTiZ44TfMKZIp78 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-usTiZ44TfMKZIp78 rect.text{fill:none;stroke-width:0;}#mermaid-svg-usTiZ44TfMKZIp78 .icon-shape,#mermaid-svg-usTiZ44TfMKZIp78 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-usTiZ44TfMKZIp78 .icon-shape p,#mermaid-svg-usTiZ44TfMKZIp78 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-usTiZ44TfMKZIp78 .icon-shape rect,#mermaid-svg-usTiZ44TfMKZIp78 .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-usTiZ44TfMKZIp78 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-usTiZ44TfMKZIp78 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-usTiZ44TfMKZIp78 :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
是 true
否 false
完成引导
点击跳过
应用启动
显示启动页持续2秒
检查是否首次使用PreferencesHelper.isFirstLaunch
显示引导页IntroScreen
显示主页面MyHomePage
用户操作
保存首次使用标志setNotFirstLaunch
标记已非首次启动
⚠️ 常见错误及解决方案
❌ 错误 1:依赖安装失败
错误信息:
Running "flutter pub get" in ffohnotes…
pub get failed
可能原因:
解决方案:
# 1. 检查网络连接
ping pub.dev
# 2. 清理缓存后重新安装
flutter clean
flutter pub get
# 3. 检查 pubspec.yaml 语法
# 确保缩进正确(使用空格,不要使用 Tab)
# 确保版本号格式正确(如 ^3.1.0)
# 4. 使用国内镜像(如果网络较慢)
export PUB_HOSTED_URL=https://pub.flutter-io.cn
export FLUTTER_STORAGE_BASE_URL=https://storage.flutter-io.cn
flutter pub get
❌ 错误 2:图片资源找不到
错误信息:
Unable to load asset: assets/images/intro_1.png
可能原因:
解决方案:
// 方案1:检查图片是否存在
// 确保 assets/images/intro_1.png 文件存在
// 方案2:在 pubspec.yaml 中配置资源路径
flutter:
assets:
– assets/images/
// 方案3:使用占位符(推荐)
// intro_slider 会自动处理图片加载失败的情况
// 如果图片不存在,会显示占位符,不会导致应用崩溃
// 方案4:不提供图片路径(可选)
Slide(
title: "欢迎使用天气预报",
description: "实时掌握天气变化…",
// pathImage: "assets/images/intro_1.png", // 注释掉或删除
backgroundColor: const Color(0xFF64B5F6),
// …
)
❌ 错误 3:SharedPreferences 初始化失败
错误信息:
PlatformException(channel-error, Unable to establish connection on channel., null, null)
可能原因:
解决方案:
Android 配置(android/app/src/main/AndroidManifest.xml):
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!– 添加存储权限(如果需要) –>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<application
android:label="天气预报"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">
<!– … –>
</application>
</manifest>
iOS 配置(通常不需要额外配置):
- shared_preferences 在 iOS 上使用 UserDefaults,通常不需要额外权限
错误处理:
static Future<bool> isFirstLaunch() async {
try {
final prefs = await SharedPreferences.getInstance();
return prefs.getBool(_keyIsFirstLaunch) ?? true;
} catch (e) {
// 如果初始化失败,返回 true(显示引导页)
debugPrint('SharedPreferences 初始化失败: $e');
return true;
}
}
❌ 错误 4:引导页不显示
错误信息:
- 应用启动后直接进入主页面,没有显示引导页
问题诊断流程:
#mermaid-svg-EO0apMDv2TRbyuYj{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-EO0apMDv2TRbyuYj .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-EO0apMDv2TRbyuYj .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-EO0apMDv2TRbyuYj .error-icon{fill:#552222;}#mermaid-svg-EO0apMDv2TRbyuYj .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-EO0apMDv2TRbyuYj .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-EO0apMDv2TRbyuYj .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-EO0apMDv2TRbyuYj .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-EO0apMDv2TRbyuYj .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-EO0apMDv2TRbyuYj .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-EO0apMDv2TRbyuYj .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-EO0apMDv2TRbyuYj .marker{fill:#333333;stroke:#333333;}#mermaid-svg-EO0apMDv2TRbyuYj .marker.cross{stroke:#333333;}#mermaid-svg-EO0apMDv2TRbyuYj svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-EO0apMDv2TRbyuYj p{margin:0;}#mermaid-svg-EO0apMDv2TRbyuYj .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-EO0apMDv2TRbyuYj .cluster-label text{fill:#333;}#mermaid-svg-EO0apMDv2TRbyuYj .cluster-label span{color:#333;}#mermaid-svg-EO0apMDv2TRbyuYj .cluster-label span p{background-color:transparent;}#mermaid-svg-EO0apMDv2TRbyuYj .label text,#mermaid-svg-EO0apMDv2TRbyuYj span{fill:#333;color:#333;}#mermaid-svg-EO0apMDv2TRbyuYj .node rect,#mermaid-svg-EO0apMDv2TRbyuYj .node circle,#mermaid-svg-EO0apMDv2TRbyuYj .node ellipse,#mermaid-svg-EO0apMDv2TRbyuYj .node polygon,#mermaid-svg-EO0apMDv2TRbyuYj .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-EO0apMDv2TRbyuYj .rough-node .label text,#mermaid-svg-EO0apMDv2TRbyuYj .node .label text,#mermaid-svg-EO0apMDv2TRbyuYj .image-shape .label,#mermaid-svg-EO0apMDv2TRbyuYj .icon-shape .label{text-anchor:middle;}#mermaid-svg-EO0apMDv2TRbyuYj .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-EO0apMDv2TRbyuYj .rough-node .label,#mermaid-svg-EO0apMDv2TRbyuYj .node .label,#mermaid-svg-EO0apMDv2TRbyuYj .image-shape .label,#mermaid-svg-EO0apMDv2TRbyuYj .icon-shape .label{text-align:center;}#mermaid-svg-EO0apMDv2TRbyuYj .node.clickable{cursor:pointer;}#mermaid-svg-EO0apMDv2TRbyuYj .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-EO0apMDv2TRbyuYj .arrowheadPath{fill:#333333;}#mermaid-svg-EO0apMDv2TRbyuYj .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-EO0apMDv2TRbyuYj .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-EO0apMDv2TRbyuYj .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-EO0apMDv2TRbyuYj .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-EO0apMDv2TRbyuYj .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-EO0apMDv2TRbyuYj .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-EO0apMDv2TRbyuYj .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-EO0apMDv2TRbyuYj .cluster text{fill:#333;}#mermaid-svg-EO0apMDv2TRbyuYj .cluster span{color:#333;}#mermaid-svg-EO0apMDv2TRbyuYj div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-EO0apMDv2TRbyuYj .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-EO0apMDv2TRbyuYj rect.text{fill:none;stroke-width:0;}#mermaid-svg-EO0apMDv2TRbyuYj .icon-shape,#mermaid-svg-EO0apMDv2TRbyuYj .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-EO0apMDv2TRbyuYj .icon-shape p,#mermaid-svg-EO0apMDv2TRbyuYj .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-EO0apMDv2TRbyuYj .icon-shape rect,#mermaid-svg-EO0apMDv2TRbyuYj .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-EO0apMDv2TRbyuYj .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-EO0apMDv2TRbyuYj .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-EO0apMDv2TRbyuYj :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
返回 false
返回 true
未导入
已导入
setState 未调用
状态切换错误
是
否
引导页不显示
检查 isFirstLaunch 返回值
调用 resetFirstLaunch重置标志
检查组件集成
添加 import 语句
检查状态管理
确保调用 setState
检查 PageState 枚举
重新运行应用
引导页是否显示?
问题解决
查看调试日志
检查回调函数
可能原因:
解决方案:
// 1. 检查首次使用标志
// 在调试时,可以重置标志来测试引导页
await PreferencesHelper.resetFirstLaunch();
// 2. 添加调试日志
void _onSplashComplete() async {
if (!mounted) return;
final isFirst = await PreferencesHelper.isFirstLaunch();
debugPrint('是否首次启动: $isFirst'); // 添加日志
if (mounted) {
setState(() {
if (isFirst) {
_pageState = PageState.intro;
debugPrint('切换到引导页'); // 添加日志
} else {
_pageState = PageState.home;
debugPrint('切换到主页面'); // 添加日志
}
});
}
}
// 3. 检查引导页组件是否正确导入
import 'screens/intro_screen.dart';
// 4. 确保 IntroScreen 组件正确创建
case PageState.intro:
return IntroScreen(
onDone: _onIntroComplete, // 确保回调函数正确传递
);
❌ 错误 5:按钮点击无响应
错误信息:
- 点击"跳过"或"开始使用"按钮没有反应
问题排查流程:
#mermaid-svg-43F8sQk4CgUGc1p1{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-43F8sQk4CgUGc1p1 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-43F8sQk4CgUGc1p1 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-43F8sQk4CgUGc1p1 .error-icon{fill:#552222;}#mermaid-svg-43F8sQk4CgUGc1p1 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-43F8sQk4CgUGc1p1 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-43F8sQk4CgUGc1p1 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-43F8sQk4CgUGc1p1 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-43F8sQk4CgUGc1p1 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-43F8sQk4CgUGc1p1 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-43F8sQk4CgUGc1p1 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-43F8sQk4CgUGc1p1 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-43F8sQk4CgUGc1p1 .marker.cross{stroke:#333333;}#mermaid-svg-43F8sQk4CgUGc1p1 svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-43F8sQk4CgUGc1p1 p{margin:0;}#mermaid-svg-43F8sQk4CgUGc1p1 .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-43F8sQk4CgUGc1p1 .cluster-label text{fill:#333;}#mermaid-svg-43F8sQk4CgUGc1p1 .cluster-label span{color:#333;}#mermaid-svg-43F8sQk4CgUGc1p1 .cluster-label span p{background-color:transparent;}#mermaid-svg-43F8sQk4CgUGc1p1 .label text,#mermaid-svg-43F8sQk4CgUGc1p1 span{fill:#333;color:#333;}#mermaid-svg-43F8sQk4CgUGc1p1 .node rect,#mermaid-svg-43F8sQk4CgUGc1p1 .node circle,#mermaid-svg-43F8sQk4CgUGc1p1 .node ellipse,#mermaid-svg-43F8sQk4CgUGc1p1 .node polygon,#mermaid-svg-43F8sQk4CgUGc1p1 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-43F8sQk4CgUGc1p1 .rough-node .label text,#mermaid-svg-43F8sQk4CgUGc1p1 .node .label text,#mermaid-svg-43F8sQk4CgUGc1p1 .image-shape .label,#mermaid-svg-43F8sQk4CgUGc1p1 .icon-shape .label{text-anchor:middle;}#mermaid-svg-43F8sQk4CgUGc1p1 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-43F8sQk4CgUGc1p1 .rough-node .label,#mermaid-svg-43F8sQk4CgUGc1p1 .node .label,#mermaid-svg-43F8sQk4CgUGc1p1 .image-shape .label,#mermaid-svg-43F8sQk4CgUGc1p1 .icon-shape .label{text-align:center;}#mermaid-svg-43F8sQk4CgUGc1p1 .node.clickable{cursor:pointer;}#mermaid-svg-43F8sQk4CgUGc1p1 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-43F8sQk4CgUGc1p1 .arrowheadPath{fill:#333333;}#mermaid-svg-43F8sQk4CgUGc1p1 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-43F8sQk4CgUGc1p1 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-43F8sQk4CgUGc1p1 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-43F8sQk4CgUGc1p1 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-43F8sQk4CgUGc1p1 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-43F8sQk4CgUGc1p1 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-43F8sQk4CgUGc1p1 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-43F8sQk4CgUGc1p1 .cluster text{fill:#333;}#mermaid-svg-43F8sQk4CgUGc1p1 .cluster span{color:#333;}#mermaid-svg-43F8sQk4CgUGc1p1 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-43F8sQk4CgUGc1p1 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-43F8sQk4CgUGc1p1 rect.text{fill:none;stroke-width:0;}#mermaid-svg-43F8sQk4CgUGc1p1 .icon-shape,#mermaid-svg-43F8sQk4CgUGc1p1 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-43F8sQk4CgUGc1p1 .icon-shape p,#mermaid-svg-43F8sQk4CgUGc1p1 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-43F8sQk4CgUGc1p1 .icon-shape rect,#mermaid-svg-43F8sQk4CgUGc1p1 .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-43F8sQk4CgUGc1p1 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-43F8sQk4CgUGc1p1 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-43F8sQk4CgUGc1p1 :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
未传递
已传递
未实现
已实现
未调用 widget.onDone
已调用
是
否
按钮点击无响应
检查回调函数传递
添加 onDone 参数
检查回调函数实现
实现 _onIntroComplete
检查 IntroScreen 内部调用
确保调用 widget.onDone
添加调试日志
查看控制台输出
日志是否打印?
回调函数正常执行
检查 Widget 生命周期
可能原因:
解决方案:
// 1. 检查回调函数是否正确传递
IntroScreen(
onDone: _onIntroComplete, // 确保传递了回调函数
)
// 2. 确保回调函数已实现
void _onIntroComplete() async {
debugPrint('引导页完成回调被调用'); // 添加日志验证
await PreferencesHelper.setNotFirstLaunch();
if (mounted) {
setState(() {
_pageState = PageState.home;
});
}
}
// 3. 检查 IntroScreen 内部是否正确调用回调
onDonePress: () {
widget.onDone(); // 确保调用了外部传入的回调
},
onSkipPress: () {
widget.onDone(); // 确保调用了外部传入的回调
},
❌ 错误 6:页面指示器不显示
错误信息:
- 引导页底部没有显示页面指示器(小圆点)
可能原因:
解决方案:
// 1. 检查指示器配置
indicatorConfig: IndicatorConfig(
sizeIndicator: 10, // 确保大小不为 0
colorIndicator: Colors.white, // 确保颜色与背景色不同
colorActiveIndicator: Colors.white.withOpacity(0.5),
typeIndicatorAnimation: TypeIndicatorAnimation.sizeTransition,
),
// 2. 如果背景是白色,使用深色指示器
indicatorConfig: IndicatorConfig(
sizeIndicator: 10,
colorIndicator: Colors.blue, // 使用深色
colorActiveIndicator: Colors.blue.withOpacity(0.5),
typeIndicatorAnimation: TypeIndicatorAnimation.sizeTransition,
),
❌ 错误 7:滑动不流畅
错误信息:
- 左右滑动引导页时卡顿或不流畅
可能原因:
解决方案:
// 1. 优化图片大小
// 建议图片尺寸:1080×1920 或 750×1334
// 使用图片压缩工具减小文件大小
// 2. 减少动画效果
indicatorConfig: IndicatorConfig(
typeIndicatorAnimation: TypeIndicatorAnimation.none, // 禁用动画
),
// 3. 使用占位符代替大图片
// 如果图片加载慢,可以先显示占位符
Slide(
title: "欢迎使用天气预报",
description: "实时掌握天气变化…",
// pathImage: "assets/images/intro_1.png", // 不提供图片
backgroundColor: const Color(0xFF64B5F6),
// …
)
🔧 进阶功能
1️⃣ 自定义引导页样式
自定义按钮样式:
IntroSlider(
slides: slides,
// 自定义跳过按钮
renderSkipBtn: () {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.3),
borderRadius: BorderRadius.circular(20),
border: Border.all(color: Colors.white, width: 2),
),
child: const Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.close, color: Colors.white, size: 18),
SizedBox(width: 4),
Text(
"跳过",
style: TextStyle(
color: Colors.white,
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
],
),
);
},
// 自定义完成按钮
renderDoneBtn: () {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 30, vertical: 12),
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Colors.white, Colors.blue.shade100],
),
borderRadius: BorderRadius.circular(25),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.2),
blurRadius: 8,
offset: const Offset(0, 4),
),
],
),
child: const Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(
"开始使用",
style: TextStyle(
color: Color(0xFF1565C0),
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
SizedBox(width: 8),
Icon(Icons.arrow_forward, color: Color(0xFF1565C0), size: 20),
],
),
);
},
)
自定义页面布局:
// 使用自定义 Widget 构建页面内容
Slide(
title: "欢迎使用天气预报",
description: "实时掌握天气变化…",
// 使用自定义 Widget
widgetDescription: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.wb_sunny, size: 100, color: Colors.white),
const SizedBox(height: 20),
const Text(
"欢迎使用天气预报",
style: TextStyle(
fontSize: 28,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
const SizedBox(height: 16),
const Text(
"实时掌握天气变化,为您的生活出行提供精准的天气信息",
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 16,
color: Colors.white,
),
),
],
),
backgroundColor: const Color(0xFF64B5F6),
)
2️⃣ 添加页面切换动画
IntroSlider(
slides: slides,
// 页面切换动画配置
animationDuration: const Duration(milliseconds: 300),
// 滑动方向(水平或垂直)
verticalScrollbarBehavior: ScrollbarBehavior.HIDE,
)
3️⃣ 根据设备语言显示不同内容
void _initSlides() {
// 获取设备语言
final locale = Localizations.localeOf(context);
final isChinese = locale.languageCode == 'zh';
slides = [
Slide(
title: isChinese ? "欢迎使用天气预报" : "Welcome to Weather App",
description: isChinese
? "实时掌握天气变化,为您的生活出行提供精准的天气信息"
: "Get real-time weather updates for your daily life and travel",
backgroundColor: const Color(0xFF64B5F6),
titleColor: Colors.white,
descriptionColor: Colors.white,
),
// … 其他页面
];
}
4️⃣ 添加页面切换监听
IntroSlider(
slides: slides,
// 页面切换回调
onTabChangeCompleted: (index) {
debugPrint('切换到第 ${index + 1} 页');
// 可以在这里添加页面切换动画、统计等
},
)
5️⃣ 条件显示引导页
版本更新检测流程:
#mermaid-svg-cqI175uDyD3o1OPM{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-cqI175uDyD3o1OPM .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-cqI175uDyD3o1OPM .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-cqI175uDyD3o1OPM .error-icon{fill:#552222;}#mermaid-svg-cqI175uDyD3o1OPM .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-cqI175uDyD3o1OPM .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-cqI175uDyD3o1OPM .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-cqI175uDyD3o1OPM .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-cqI175uDyD3o1OPM .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-cqI175uDyD3o1OPM .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-cqI175uDyD3o1OPM .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-cqI175uDyD3o1OPM .marker{fill:#333333;stroke:#333333;}#mermaid-svg-cqI175uDyD3o1OPM .marker.cross{stroke:#333333;}#mermaid-svg-cqI175uDyD3o1OPM svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-cqI175uDyD3o1OPM p{margin:0;}#mermaid-svg-cqI175uDyD3o1OPM .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-cqI175uDyD3o1OPM .cluster-label text{fill:#333;}#mermaid-svg-cqI175uDyD3o1OPM .cluster-label span{color:#333;}#mermaid-svg-cqI175uDyD3o1OPM .cluster-label span p{background-color:transparent;}#mermaid-svg-cqI175uDyD3o1OPM .label text,#mermaid-svg-cqI175uDyD3o1OPM span{fill:#333;color:#333;}#mermaid-svg-cqI175uDyD3o1OPM .node rect,#mermaid-svg-cqI175uDyD3o1OPM .node circle,#mermaid-svg-cqI175uDyD3o1OPM .node ellipse,#mermaid-svg-cqI175uDyD3o1OPM .node polygon,#mermaid-svg-cqI175uDyD3o1OPM .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-cqI175uDyD3o1OPM .rough-node .label text,#mermaid-svg-cqI175uDyD3o1OPM .node .label text,#mermaid-svg-cqI175uDyD3o1OPM .image-shape .label,#mermaid-svg-cqI175uDyD3o1OPM .icon-shape .label{text-anchor:middle;}#mermaid-svg-cqI175uDyD3o1OPM .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-cqI175uDyD3o1OPM .rough-node .label,#mermaid-svg-cqI175uDyD3o1OPM .node .label,#mermaid-svg-cqI175uDyD3o1OPM .image-shape .label,#mermaid-svg-cqI175uDyD3o1OPM .icon-shape .label{text-align:center;}#mermaid-svg-cqI175uDyD3o1OPM .node.clickable{cursor:pointer;}#mermaid-svg-cqI175uDyD3o1OPM .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-cqI175uDyD3o1OPM .arrowheadPath{fill:#333333;}#mermaid-svg-cqI175uDyD3o1OPM .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-cqI175uDyD3o1OPM .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-cqI175uDyD3o1OPM .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-cqI175uDyD3o1OPM .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-cqI175uDyD3o1OPM .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-cqI175uDyD3o1OPM .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-cqI175uDyD3o1OPM .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-cqI175uDyD3o1OPM .cluster text{fill:#333;}#mermaid-svg-cqI175uDyD3o1OPM .cluster span{color:#333;}#mermaid-svg-cqI175uDyD3o1OPM div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-cqI175uDyD3o1OPM .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-cqI175uDyD3o1OPM rect.text{fill:none;stroke-width:0;}#mermaid-svg-cqI175uDyD3o1OPM .icon-shape,#mermaid-svg-cqI175uDyD3o1OPM .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-cqI175uDyD3o1OPM .icon-shape p,#mermaid-svg-cqI175uDyD3o1OPM .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-cqI175uDyD3o1OPM .icon-shape rect,#mermaid-svg-cqI175uDyD3o1OPM .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-cqI175uDyD3o1OPM .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-cqI175uDyD3o1OPM .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-cqI175uDyD3o1OPM :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
不同
相同
是
否
检查是否显示引导页
获取上次引导页版本last_intro_version
获取当前应用版本currentVersion
版本是否相同?
版本已更新
检查首次启动标志
保存当前版本号
返回 true显示引导页
是否首次启动?
返回 false不显示引导页
代码实现:
// 根据应用版本决定是否显示引导页
Future<bool> shouldShowIntro() async {
final prefs = await SharedPreferences.getInstance();
final lastVersion = prefs.getString('last_intro_version');
final currentVersion = '1.0.0'; // 从 package_info_plus 获取
// 如果版本更新,重新显示引导页
if (lastVersion != currentVersion) {
await prefs.setString('last_intro_version', currentVersion);
return true;
}
// 检查是否首次启动
return prefs.getBool('is_first_launch') ?? true;
}
📚 完整代码示例
文件结构
#mermaid-svg-8tdbx43g7KGMCC1W{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-8tdbx43g7KGMCC1W .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-8tdbx43g7KGMCC1W .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-8tdbx43g7KGMCC1W .error-icon{fill:#552222;}#mermaid-svg-8tdbx43g7KGMCC1W .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-8tdbx43g7KGMCC1W .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-8tdbx43g7KGMCC1W .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-8tdbx43g7KGMCC1W .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-8tdbx43g7KGMCC1W .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-8tdbx43g7KGMCC1W .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-8tdbx43g7KGMCC1W .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-8tdbx43g7KGMCC1W .marker{fill:#333333;stroke:#333333;}#mermaid-svg-8tdbx43g7KGMCC1W .marker.cross{stroke:#333333;}#mermaid-svg-8tdbx43g7KGMCC1W svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-8tdbx43g7KGMCC1W p{margin:0;}#mermaid-svg-8tdbx43g7KGMCC1W .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-8tdbx43g7KGMCC1W .cluster-label text{fill:#333;}#mermaid-svg-8tdbx43g7KGMCC1W .cluster-label span{color:#333;}#mermaid-svg-8tdbx43g7KGMCC1W .cluster-label span p{background-color:transparent;}#mermaid-svg-8tdbx43g7KGMCC1W .label text,#mermaid-svg-8tdbx43g7KGMCC1W span{fill:#333;color:#333;}#mermaid-svg-8tdbx43g7KGMCC1W .node rect,#mermaid-svg-8tdbx43g7KGMCC1W .node circle,#mermaid-svg-8tdbx43g7KGMCC1W .node ellipse,#mermaid-svg-8tdbx43g7KGMCC1W .node polygon,#mermaid-svg-8tdbx43g7KGMCC1W .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-8tdbx43g7KGMCC1W .rough-node .label text,#mermaid-svg-8tdbx43g7KGMCC1W .node .label text,#mermaid-svg-8tdbx43g7KGMCC1W .image-shape .label,#mermaid-svg-8tdbx43g7KGMCC1W .icon-shape .label{text-anchor:middle;}#mermaid-svg-8tdbx43g7KGMCC1W .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-8tdbx43g7KGMCC1W .rough-node .label,#mermaid-svg-8tdbx43g7KGMCC1W .node .label,#mermaid-svg-8tdbx43g7KGMCC1W .image-shape .label,#mermaid-svg-8tdbx43g7KGMCC1W .icon-shape .label{text-align:center;}#mermaid-svg-8tdbx43g7KGMCC1W .node.clickable{cursor:pointer;}#mermaid-svg-8tdbx43g7KGMCC1W .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-8tdbx43g7KGMCC1W .arrowheadPath{fill:#333333;}#mermaid-svg-8tdbx43g7KGMCC1W .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-8tdbx43g7KGMCC1W .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-8tdbx43g7KGMCC1W .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-8tdbx43g7KGMCC1W .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-8tdbx43g7KGMCC1W .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-8tdbx43g7KGMCC1W .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-8tdbx43g7KGMCC1W .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-8tdbx43g7KGMCC1W .cluster text{fill:#333;}#mermaid-svg-8tdbx43g7KGMCC1W .cluster span{color:#333;}#mermaid-svg-8tdbx43g7KGMCC1W div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-8tdbx43g7KGMCC1W .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-8tdbx43g7KGMCC1W rect.text{fill:none;stroke-width:0;}#mermaid-svg-8tdbx43g7KGMCC1W .icon-shape,#mermaid-svg-8tdbx43g7KGMCC1W .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-8tdbx43g7KGMCC1W .icon-shape p,#mermaid-svg-8tdbx43g7KGMCC1W .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-8tdbx43g7KGMCC1W .icon-shape rect,#mermaid-svg-8tdbx43g7KGMCC1W .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-8tdbx43g7KGMCC1W .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-8tdbx43g7KGMCC1W .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-8tdbx43g7KGMCC1W :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
lib/
main.dart应用入口
screens/
utils/
splash_screen.dart启动页
intro_screen.dart引导页
preferences_helper.dart首选项管理工具
SplashWrapper页面状态管理
MyHomePage主页面
目录说明:
lib/
├── main.dart # 应用入口
├── screens/
│ ├── splash_screen.dart # 启动页
│ └── intro_screen.dart # 引导页
└── utils/
└── preferences_helper.dart # 首选项管理工具
完整代码
所有代码文件已在前面章节提供,这里不再重复。完整的项目代码包括:
运行项目
# 1. 安装依赖
flutter pub get
# 2. 运行应用
flutter run
# 3. 测试引导页
# 首次运行会显示引导页
# 完成引导后,再次运行不会显示引导页
# 4. 重置引导页(用于测试)
# 在代码中调用:
await PreferencesHelper.resetFirstLaunch();
📖 总结
本教程详细介绍了如何使用 intro_slider 三方库实现 Flutter 应用引导页,包括:
✅ 引入三方库步骤:添加依赖、配置资源、安装依赖 ✅ 具体页面实现:创建工具类、引导页组件、集成到主应用 ✅ 常见错误解决:依赖安装、资源加载、状态管理等问题 ✅ 进阶功能:自定义样式、多语言支持、条件显示等
🎯 关键要点
📚 相关资源
- intro_slider 官方文档
- shared_preferences 官方文档
- Flutter 官方文档
🎉 祝你开发顺利! 🚀
欢迎加入开源鸿蒙跨平台社区




