Flutter實戰(zhàn)--美食App(二)

鎮(zhèn)樓美女

上節(jié)我們簡單的處理了下程序的入口函數(shù)文件main.dart,在其中我們讓程序啟動后進入的第一個頁面是閃屏頁SplashPage。現(xiàn)在市面上絕大多數(shù)App啟動后都會有個閃屏頁,一般都是展示一張應(yīng)用相關(guān)的圖片或是放置一個廣告位用來展示廣告以賺取收入。那么今天我們就來實現(xiàn)個簡單的閃屏頁。先來看看效果圖:

閃屏頁
  • SplashPage

lib目錄下新建一個目錄page,添加splash_page.dart,該界面主要實現(xiàn)如下功能:

1.放置一張圖片或動態(tài)圖(gif),類似于廣告展示圖;
2.右上角放置一個倒計時按鈕,默認顯示3s,3s內(nèi)點擊按鈕跳轉(zhuǎn)HomePage界面,否則倒計時結(jié)束后自動跳轉(zhuǎn)到HomePage界面。

  • 背景圖
    在根目錄下新建一個assets/images/目錄用來放置App中需要用到的圖片,我們在目錄下放置一張背景圖bg.png(上面gif動圖中的黑色背景圖,自己PS的圖片。),然后到根目錄下的pubspec.yaml文件中添加下面代碼
# The following section is specific to Flutter.
flutter:
  assets:
   - assets/images/

添加完之后再終端下執(zhí)行flutter pub get或點擊VSCode右上角的刷新按鈕也行,這樣我們就可以在代碼中引用剛剛添加的本地圖片了。

因為倒計時要不斷的刷新界面,所以SplashPage也是一個StatefulWidget。頁面的布局就是背景圖上再放置一個倒計時按鈕,這里使用FlutterStack部件,在該部件里我們可以在確定的位置放置我們想要放置的子部件。

  • 倒計時功能實現(xiàn)
    我們先來寫個倒計時的方法countDown,
countDown() async {
    Timer(Duration(seconds: 1), () {
      _timer = Timer.periodic(Duration(milliseconds: 1000), (t) {
        count--;
        if (count == 0) {
          navigationToHome(); //跳轉(zhuǎn)到home頁
        } else {
          setState(() {}); //刷新界面
        }
      });
      return _timer;
    });
  }

然后在initState(){}方法中調(diào)用countDown方法,這樣當(dāng)進入SplashPage界面就會執(zhí)行倒計時方法了,界面右上角上就會看到一個倒計時按鈕數(shù)字在變化。

  • 跳轉(zhuǎn)Home界面
    當(dāng)?shù)褂嫊r按鈕在3s內(nèi)未被點擊,則倒計時結(jié)束后自動跳轉(zhuǎn)到HomePage,當(dāng)在3s內(nèi)點擊按鈕則立馬跳轉(zhuǎn)到HomePage。下面我們寫個跳轉(zhuǎn)方法,該方法中首先要取消定時器Timer,具體如下:
navigationToHome() {
    _timer.cancel();
    Routes.navigateTo(context, '/home', clearStack: true);
  }

有小伙伴可能要問Routes是什么鬼?這里是使用了一個第三方插件Fluro。在pubspec.yaml文件的dependencies:下添加fluro: ^1.6.3,然后終端執(zhí)行flutter pub get加載該插件。然后在lib目錄下新建一個router文件夾,里面新建兩個文件routes.dartrouter_handler.dart,里面的內(nèi)容如下:

  • routes.dart
import 'package:fluro/fluro.dart';
import 'package:flutter/material.dart';
import 'package:icooker/router/router_handler.dart';

// 在routes.dart文件中配置路由,這里需要注意的事首頁一定要用“/”配置,其它頁無所謂
class Routes {
  static Router router;

  static String root = '/';
  static String home = '/home';

  static void configureRouters(Router router) {
    router.notFoundHandler = Handler(
        handlerFunc: (BuildContext context, Map<String, dynamic> params) {
      print('ERROR====>>>>ROUTE WAS NOT FOUND!!!');
      return;
    });

    router.define(home, handler: homeHandler); //首頁界面
  }

  // 對參數(shù)進行encode,解決參數(shù)中有特殊字符,影響fluro路由匹配
  static Future navigateTo(BuildContext context, String path,
      {Map<String, dynamic> params,
      TransitionType transition = TransitionType.native,
      bool clearStack = false}) {
     
    String query = "";
    if (params != null) {
      int index = 0;
      for (var key in params.keys) {
        var value = Uri.encodeComponent(params[key]);
        if (index == 0) {
          query = "?";
        } else {
          query = query + "\&";
        }
        query += "$key=$value";
        index++;
      }
    }
    print('navigatorTo傳遞的參數(shù):$query');
    path += query;
    return router.navigateTo(context, path,
        transition: transition, clearStack: clearStack);
  }

  //關(guān)閉當(dāng)前頁面
  static pop(BuildContext context) {
    router.pop(context);
  }
}

其中的clearStack是否清理頁面棧,即從當(dāng)前頁面跳轉(zhuǎn)到新頁面后是否關(guān)閉前一個頁面。

true: 清除,即新頁面回退無法再進入跳轉(zhuǎn)前的頁面,
false: 不清除,即從新頁面按回退按鈕還能跳轉(zhuǎn)到之前的頁面。
  • router_handler.dart
import 'package:fluro/fluro.dart';
import 'package:flutter/material.dart';
import 'package:icooker/pages/home_page.dart';

Handler homeHandler =
    Handler(handlerFunc: (BuildContext context, Map<String, dynamic> params) {
  return HomePage();
});

然后再到main.dart文件中的build方法下添加如下代碼:

@override
  Widget build(BuildContext context) {
    // 配置路由
    final router = Router();
    Routes.configureRouters(router);
    Routes.router = router;
    ... //省略
    return MaterialApp(
          debugShowCheckedModeBanner: false, //關(guān)閉banner上的Debug標識
          onGenerateRoute: Routes.router.generator,
          ... // 省略
     );
  }

再在page目錄下新建一個 home_page.dart文件,里面隨便放置一個StatefulWidget即可,此時點擊VSCode上的調(diào)試按鈕就可以在模擬器或真機上看到閃屏頁的倒計時跳轉(zhuǎn)效果了。

  • 解決Android啟動黑屏問題
    在Android機器啟動后會出現(xiàn)幾秒黑屏現(xiàn)象,debug狀態(tài)下可能黑屏的時間更長,同時手機的配置越高黑屏的時間相對也越短。我們只需要執(zhí)行以下兩步:
  • android/app/src/main/res/drawable/launch_background.xml中添加如下代碼:
<?xml version="1.0" encoding="utf-8"?>
<!-- Modify this file to customize your launch splash screen -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@android:color/white" />

    <!-- You can insert your own image assets here -->
    <!-- <item>
        <bitmap
            android:gravity="center"
            android:src="@mipmap/launch_image" />
    </item> -->
    <item>
        <bitmap 
        android:src="@mipmap/bg"/>
    </item>
</layer-list>

添加一張跟閃屏頁相同的背景圖片即可

  • android/app/src/main/res/values/styles.xml文件中添加如下代碼:
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
        <!-- Show a splash screen on the activity. Automatically removed when
             Flutter draws its first frame -->
        <item name="android:windowBackground">@drawable/launch_background</item>
        <item name="android:windowIsTranslucent">true</item>
    </style>
</resources>

再重新debug下就會發(fā)現(xiàn)黑屏的問題解決了。(ps:建議調(diào)試的時候使用真機調(diào)試,模擬器太卡而且有些效果或問題只有真機上才能出現(xiàn)。)

好了,下面放出閃屏頁的完整參考代碼,如下:

import 'dart:async';

import 'package:flutter/material.dart';
import 'package:icooker/router/routes.dart';

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

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

class _SplashPageState extends State<SplashPage> {
  Timer _timer;
  int count = 3; //默認倒計時3s

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

  countDown() async {
    Timer(Duration(seconds: 1), () {
      _timer = Timer.periodic(Duration(milliseconds: 1000), (t) {
        count--;
        if (count == 0) {
          navigationToHome(); //跳轉(zhuǎn)到home頁
        } else {
          setState(() {}); //刷新界面
        }
      });
      return _timer;
    });
  }

  navigationToHome() {
    _timer.cancel();
    Routes.navigateTo(context, '/home', clearStack: true);
  }

  @override
  Widget build(BuildContext context) {
    // debugPrint('count===$count');
    return Stack(
      alignment: Alignment(1.0, -1.0),
      children: <Widget>[
        ConstrainedBox(
          constraints: BoxConstraints.expand(),
          child: Image.asset(
            'assets/images/bg.png',
            fit: BoxFit.fill,
          ),
        ),
        Padding(
          padding: EdgeInsets.fromLTRB(0, 20.0, 4.0, 0),
          child: FlatButton(
            onPressed: () => navigationToHome(),
            color: Colors.grey,
            shape: CircleBorder(),
            child: Text(
              '${count}s',
              style: TextStyle(
                color: Colors.white,
                fontSize: 14.0,
              ),
            ),
          ),
        ),
      ],
    );
  }
}

?完整Demo請移步 iCooker 喜歡的請給個Star ☆?。?/strong>

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容