Flutter實戰 從頭擼一個「孤島」APP(No.2、閃屏Splash Page、引導頁)

洋小洋同學發表於2019-11-23

1. 前情回顧

嗨,正在掉頭髮的你們好,我是洋小洋,本集我們們接著聊一下GooGle的“親兒子”Flutter。那自從上篇文章分享之後,有一些掘友也發表了一些很有意思的評論。那我們們首先來回顧一下

1.1 讀讀評論

在這裡挑選3位的評論,覺得挺有趣,畢竟我們也不是設計師,這也不得不證明了一個產品的UI是多麼的重要,當然也是隨機在評論區,貼上他們的連結,也可以看看對方會不會有什麼技術上的專欄,大家互相學習。之後的每一段路,我也都對從評論區貼上你們的奇葩評論

1.2 上整合就

  • 掘金社群Flutter模組7天內熱榜第1

  • 掘金社群Flutter模組熱門第3

  • 掘金社群Flutter模組最新第8

  • 截止目前25贊10評論

雖然我也不太喜歡掘金的搜尋演算法,聽說更新了,期待越來越好,大家能夠分享自己對於技術的探索

2. 寫在前面

不知不覺一週又過去了,實際開發的過程中還是會有很多坑的,這個循序漸進會和大家分享,包括像Provider和後臺互動的流程等。Dio的企業化配置等。那在本集我們們還是畫介面

2.1 本章目標

Flutter實戰  從頭擼一個「孤島」APP(No.2、閃屏Splash Page、引導頁)

如圖所示,還是那麼一個Low的介面,下面的內容可能會有點無聊,不過真的很肝,期待與你相遇

2.2 分享列表

2.3 Flutter資料

Flutter實戰  從頭擼一個「孤島」APP(No.2、閃屏Splash Page、引導頁)

Flutter實戰  從頭擼一個「孤島」APP(No.2、閃屏Splash Page、引導頁)

Flutter實戰  從頭擼一個「孤島」APP(No.2、閃屏Splash Page、引導頁)

Flutter實戰  從頭擼一個「孤島」APP(No.2、閃屏Splash Page、引導頁)

3. 著手開發

3.1 vscode 外掛

  • Flutter 語法檢測、程式碼補全、程式碼重構、執行除錯和熱過載
  • Dart
  • Flutter Widget Snippets Widget 程式碼片段
  • Awesome Flutter Snippets 提供常用函式的程式碼片段

那由於一個APP 一上來就直接登入頁或者註冊頁。是有點生硬的,對使用者來說是極為不友好的,凡事都要慢慢來,有個過程不是嗎?其實在閃屏的過程中,是會做一些判斷的,你如判斷使用者有沒有登入等

3.2 拉取程式碼

發現我們並沒有提交更新

Flutter實戰  從頭擼一個「孤島」APP(No.2、閃屏Splash Page、引導頁)

  • 新建開發分支

接著我們們新建一個開發分支,用來記錄新的一個章節,這個章節我們們要做的是閃屏和引導頁,如題

Flutter實戰  從頭擼一個「孤島」APP(No.2、閃屏Splash Page、引導頁)

  • DEBUG 除錯

Flutter實戰  從頭擼一個「孤島」APP(No.2、閃屏Splash Page、引導頁)

在上週的時候 我們是通過在專案的根目錄下flutter run執行專案,然後Rr進行切換

本週我們們藉助Vscode debug 除錯模式

3.3 公共變數處理Global

在評論區,有掘友提到,底部的導航也太大,其實我們是已經適配過螢幕的不是嗎?通過一個外掛flutter_screenutil,當然也可以採取其他的方式,比如MediaQuery可以拿到widget以及裝置的的寬高

那麼什麼是全域性變數呢, 全域性變數就是單純指會貫穿整個APP生命週期的變數,用於單純的儲存一些資訊,或者封裝一些全域性工具和方法的物件。

我們先打算新建一個global.dart用來存放比如說常用的寬度、高度、以及字型大小

cd utils
copy nul > global.dart // 新建一個global.dart(windows下)
複製程式碼
import 'package:flutter_screenutil/flutter_screenutil.dart';

/// 頁面常見的寬度與高度
// 寬度
double width100 = ScreenUtil.getInstance().setWidth(100);
// 高度
double height100 = ScreenUtil.getInstance().setHeight(100);

複製程式碼

接著我們在底部的導航欄看下直接用我們的變數,當然第一步還是引入

import '../utils/global.dart';
複製程式碼

我們來進行測試下,把上一段結尾我們們引入的圖片全部先刪除,寫上一段測試文字

Flutter實戰  從頭擼一個「孤島」APP(No.2、閃屏Splash Page、引導頁)

當我們重啟之後,顯然是可以的

3.4 閃屏 splash screen

我們第一步還是新建一個page頁面,並命名為splash_screen_page

/// 閃屏的頁面
import 'package:flutter/material.dart';

class SplashScreenPage extends StatelessWidget {
  const SplashScreenPage({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        child: Text('閃屏頁面'),
      ),
    );
  }
}

複製程式碼

然後在main.dart引用並使用,這時我們已經不再引入底部的導航介面了

   return MaterialApp(
        debugShowCheckedModeBanner: false, // 去除除錯
        title: '孤島',
        theme: ThemeData(
          primarySwatch: Colors.blue,
        ),
        home: SplashScreenPage()); // 這裡使用引導頁,也就是說當使用者一進來的時候,是一個閃屏
  }
複製程式碼

接著我們們就寫屬於這個孤島APP 閃屏頁,首先了解下幾個部件

  • SingleChildScrollView 主要是控制裡邊的部件溢位,可以進行滾動

Flutter實戰  從頭擼一個「孤島」APP(No.2、閃屏Splash Page、引導頁)

  • BoxDecoration 主要是對容器進行修飾的,比如背景色,寬高等

Flutter實戰  從頭擼一個「孤島」APP(No.2、閃屏Splash Page、引導頁)

這裡我們使用一下漸變 gradient

 decoration: BoxDecoration(
            gradient: LinearGradient(
                colors: [
              // 線性漸變 有個漸變的過程
              Color.fromRGBO(0, 0, 0, 0.2),
              Color.fromRGBO(0, 0, 0, 0.4)
            ],
                begin: FractionalOffset.topCenter, // 頂部居中
                end: FractionalOffset.bottomCenter)), // 
複製程式碼

效果是這個樣子的

Flutter實戰  從頭擼一個「孤島」APP(No.2、閃屏Splash Page、引導頁)

這個時候應用的第一個頁面便是閃屏頁面,然後我們寫這個頁面的主要內容

  child: Container(
              child: Column(
                children: <Widget>[
                  Padding(
                    padding: EdgeInsets.only(top: 30),
                  ),
                    //  
                  Text('孤島',
                      style: TextStyle(
                          fontSize: fontSize200, fontWeight: FontWeight.w600))
                ],
              ),
            ),
複製程式碼

這裡注意,fontSize: fontSize200我們直接使用公共的global的宣告定義好的大小就可

好了 跑一下

Flutter實戰  從頭擼一個「孤島」APP(No.2、閃屏Splash Page、引導頁)

不盡如意的是,報了錯誤

The method '/' was called on null.
複製程式碼

這個問題很簡單,其實是我們在使用螢幕適配的時候,並沒有初始化

Flutter實戰  從頭擼一個「孤島」APP(No.2、閃屏Splash Page、引導頁)

顯然這樣就可以了,我們接著插入一張圖片,放在這兒就會好些了

  decoration: BoxDecoration(
            image: DecorationImage(
              image: AssetImage(assetName)
            )
          ),

複製程式碼

放什麼圖片呢,就還是放一張保守點的吧,感覺她越來越不像《孤島App》了

**圖片資源來自B站UP主 **wlop- (如有侵權,請聯絡 Blog

老規矩我們們還是需要在pubspec.yaml中配置一下,閃屏靜態時候的樣子我們們暫且這個樣子

0215

還記得我們上一段旅程有一起看過MaterialApp 的原始碼

  const MaterialApp({
    Key key,
    this.navigatorKey,
    this.home,
    this.routes = const <String, WidgetBuilder>{}, // 我們暫時會用到這個路由的配置
    this.initialRoute,
    this.onGenerateRoute,
    this.onUnknownRoute,
    this.navigatorObservers = const <NavigatorObserver>[],
    this.builder,
    this.title = '',
    this.onGenerateTitle,
    this.color,
    this.theme,
    this.darkTheme,
    this.themeMode = ThemeMode.system,
    this.locale,
    this.localizationsDelegates,
    this.localeListResolutionCallback,
    this.localeResolutionCallback,
    this.supportedLocales = const <Locale>[Locale('en', 'US')],
    this.debugShowMaterialGrid = false,
    this.showPerformanceOverlay = false,
    this.checkerboardRasterCacheImages = false,
    this.checkerboardOffscreenLayers = false,
    this.showSemanticsDebugger = false,
    this.debugShowCheckedModeBanner = true,
  })

複製程式碼

主要目的便是當閃屏結束的時候,跳轉到引導頁面

  return MaterialApp(
      debugShowCheckedModeBanner: false, // 去除除錯
      title: '孤島',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: SplashScreenPage(),
      routes: {
        'guidePages': (context) {
          return GuidePages(); // 跳轉到引導頁面
        }
      },
    );

複製程式碼

設計一個計時器,用來等計時器結束的時候,跳轉

 /// 設計一個計時器,用來等計時器結束的時候,跳轉
  jumpPage(){
    return Timer(duration, callback);
  }
/// 原始碼其實是這樣的
 factory Timer(Duration duration, void callback()) {
    if (Zone.current == Zone.root) {
      // No need to bind the callback. We know that the root's timer will
      // be invoked in the root zone.
      return Zone.current.createTimer(duration, callback);
    }
    return Zone.current
        .createTimer(duration, Zone.current.bindCallbackGuarded(callback));
  }

複製程式碼
  • duration 就是延遲
  • callback 就是回撥,在時間結束做什麼事情

由於之前我們們是用的是StatelessWidget 也就是說我們需要在一個時間呼叫頁面跳轉的方法暫時我們改用有狀態的部件StatefulWidget,完整程式碼是這樣

import 'dart:async';

/// 閃屏的頁面
import 'package:flutter/material.dart';
import '../utils/global.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';

class SplashScreenPage extends StatefulWidget {
  SplashScreenPage({Key key}) : super(key: key);

  @override
  _SplashScreenPageState createState() => _SplashScreenPageState();
}

class _SplashScreenPageState extends State<SplashScreenPage> {
  /// 設計一個計時器,用來等計時器結束的時候,跳轉
  jumpPage() {
    return Timer(Duration(milliseconds: 3000), () {
      Navigator.pushReplacementNamed(context, 'guidePages');
    });
  }

  @override
  void initState() {
    super.initState();

    jumpPage();
  }

  @override
  Widget build(BuildContext context) {
    ScreenUtil.instance = ScreenUtil(width: 750, height: 1334)..init(context);
    return Scaffold(
        backgroundColor: Colors.white, // 背景色
        body: Container(
          decoration: BoxDecoration(
              image: DecorationImage(
                  image: AssetImage('images/splash_screen.jpg'),
                  fit: BoxFit.cover)), // 新增背景圖片
          child: Container(
            child: Center(
              child: SingleChildScrollView(
                child: Container(
                  child: Column(
                    children: <Widget>[
                      Padding(
                        padding: EdgeInsets.only(top: 30),
                      ),
                      Text('歡迎來到孤島',
                          style: TextStyle(
                              fontSize: fontSize40,
                              color: Colors.white10,
                              fontWeight: FontWeight.w600)),
                      SizedBox(
                        height: height100,
                      ),
                      Text('By 洋小洋',
                          style: TextStyle(
                              fontSize: fontSize40,
                              color: Colors.white10,
                              fontWeight: FontWeight.w600))
                    ],
                  ),
                ),
              ),
            ),
            decoration: BoxDecoration(
                gradient: LinearGradient(
                    colors: [
                  // 線性漸變 有個漸變的過程
                  Color.fromRGBO(0, 0, 0, 0.2),
                  Color.fromRGBO(0, 0, 0, 0.5)
                ],
                    begin: FractionalOffset.topCenter, // 頂部居中
                    end: FractionalOffset.bottomCenter)), // 底部居中
          ),
        ));
  }
}


複製程式碼

好了,我們先階段性的看下一起實現的效果

Flutter實戰  從頭擼一個「孤島」APP(No.2、閃屏Splash Page、引導頁)

3.5 引導頁

在走過了閃屏之後,我們期望能有個引導頁,顧名思義就是引導使用者下一步下一步,這裡我們們採用第三方的包intro_views_flutter 2.8.0

截止目前包的版本是2.8.0

包名 傳送
intro_views_flutter intro_views_flutter
  • 將此新增到包的pubspec.yaml檔案中:

    dependencies:
      intro_views_flutter: ^2.8.0
    
    複製程式碼
  • 您可以從命令列安裝軟體包:

    $ flutter pub get
    
    複製程式碼
  • 現在,在Dart程式碼中,您可以使用:

    import 'package:intro_views_flutter/intro_views_flutter.dart';
    
    複製程式碼

一波流操作後,就可以是使用了,具體使用的方法還是需要看一下API

屬性 資料型別 描述 預設值
pageColor Color 設定頁面的顏色。 Null
mainImage Image / Widget 設定頁面的主影象。 Null
title Text / Widget 設定頁面的標題文字。 Null
body Text / Widget 設定頁面的正文。 Null
iconImageAssetPath String 設定將在頁面氣泡中顯示的圖示影象路徑。 Null
iconColor Color 設定頁面氣泡圖示的顏色。 Null
bubbleBackgroundColor Color 設定頁面氣泡背景色。 Colors.white / Color(0x88FFFFFF)
textStyle TextStyle 為標題和正文設定TextStyle title: color: Colors.white , fontSize: 50.0 body: color: Colors.white , fontSize: 24.0
titleTextStyle TextStyle 設定標題的TextStyle color: Colors.white , fontSize: 50.0
bodyTextStyle TextStyle 為正文設定TextStyle color: Colors.white , fontSize: 24.0
bubble Widget 為內部氣泡設定自定義小部件 null

那我們們就根據使用的小細則定義一個PageViewModel

PageViewModel(
        pageColor: const Color(0xFF03A9F4),
        // iconImageAssetPath: 'assets/air-hostess.png',
        iconColor: Colors.pink,
        bubbleBackgroundColor: Colors.pink,
        // bubble: Image.asset('images/jiche.jpg'),
        body: Text(
          '這是屬於你我的孤島',
        ),
        title: Text(
          'No.1',
        ),
        // titleTextStyle: TextStyle(fontFamily: 'MyFont', color: Colors.white),
        // bodyTextStyle: TextStyle(fontFamily: 'MyFont', color: Colors.white),
        mainImage: Container(
          decoration:
              BoxDecoration(border: Border.all(width: 1, color: Colors.red)),
          child: Image.asset(
            // 圖片
            'images/jiche.jpg',
            height: width750,
            width: height1314,
            fit: BoxFit.cover,
            // alignment: Alignment.center, // 居中顯示
          ),
        )),

複製程式碼

images資料夾我們們又新增了幾張圖片,用於引導頁的展示,圖片素材有的是在這兒找的

Flutter實戰  從頭擼一個「孤島」APP(No.2、閃屏Splash Page、引導頁)

Flutter實戰  從頭擼一個「孤島」APP(No.2、閃屏Splash Page、引導頁)

那現在效果就差不多了,來一起看下

Flutter實戰  從頭擼一個「孤島」APP(No.2、閃屏Splash Page、引導頁)

4. 寫在最後

很高興你能耐住性子看到這兒,尤其是在這個快節奏的生活和工作中,我們在今天的這段旅程已經完成了兩部分

  • 閃屏
  • 引導頁

寫到現在已經是凌晨2:35分了

Flutter實戰  從頭擼一個「孤島」APP(No.2、閃屏Splash Page、引導頁)

由於這周看了下這個

Flutter實戰  從頭擼一個「孤島」APP(No.2、閃屏Splash Page、引導頁)

又出去浪蕩了一圈,不過也還沒有斷更,也算對自己的一個激勵吧,所以也請你給個鼓勵,評論點贊,當然是感覺還行的話,說不定就出現在下一章節的[讀讀評論]

我是洋小洋,下回見,本節程式碼會同步更新倉庫 github.com/yayxs/flutt…


--END

相關文章