1. 程式人生 > >一個Android開發快速入門Flutter (二)

一個Android開發快速入門Flutter (二)

目錄

一個Java開發快速入門Dart

Flutter使用簡報

一個Android開發快速入門Flutter(一)

一個Android開發快速入門Flutter (二) 

前言

    接上一篇部落格,入門Flutter(一)中的內容相對來說更加全域性一些,並沒有涉及到具體控制元件的使用,本篇入門會更加深入一些,不過還是停留在總覽的地步,不會對每一個控制元件進行深入探究。

正文

如何監聽Activity中的生命週期事件

    在Android中我們通過Activity自帶的方法或者在Application中註冊ActivityLifecycleCallbacks介面進行生命週期監聽。在Flutter中當然沒有相關的概念(因為連Activity的概念也沒有)

    不過Flutter還是有方法去監聽app狀態的,否則就沒辦法響應切換到後臺這種情況了。

    先來說說監聽方法,我們可以通過繼承WidgetsBindingObserver,該類中存在一個回撥方法didChangeAppLifecycleState,用於表示當前應用狀態改變。(當然WidgetsBindingObserver 中還有其他很多狀態回撥,比如一個route 被push 或者pop,比如橫豎屏變化,比如使用者locales切換,是否存在記憶體壓力,輔助功能切換等。)

    具體程式碼如下

import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter/material.dart';

class LifecycleWatcher extends StatefulWidget {
  @override
  _LifecycleWatcherState createState() => _LifecycleWatcherState();
}

//多重繼承了 WidgetsBindingObserver
class _LifecycleWatcherState extends State<LifecycleWatcher>
    with WidgetsBindingObserver {
  AppLifecycleState _lastLifecycleState;

  //相當於初始化
  @override
  void initState() {
    super.initState();
    //註冊應用宣告週期監聽
    WidgetsBinding.instance.addObserver(this);
  }
  //相當於銷燬
  @override
  void dispose() {
    WidgetsBinding.instance.removeObserver(this);
    super.dispose();
  }
  //監聽應用宣告週期方法
  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    print("current state is $state");
    setState(() {
      _lastLifecycleState = state;
    });
  }

  @override
  Widget build(BuildContext context) {
    if (_lastLifecycleState == null)
      return Text('This widget has not observed any lifecycle changes.',
          textDirection: TextDirection.ltr);

    return Text(
        'The most recent lifecycle state this widget observed was: $_lastLifecycleState.',
        textDirection: TextDirection.ltr);
  }
}

class MyApp extends StatelessWidget {
  static const platform = const MethodChannel('app.channel.shared.data');

  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return MaterialApp(
      title: 'Sample App',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Scaffold(
        appBar: AppBar(
          title: Text("Sample App"),
        ),
        body: Center(child: LifecycleWatcher()),
        //新增一個懸浮按鈕,該按鈕點選後觸發_updateText方法
        floatingActionButton: FloatingActionButton(
          onPressed: _updateText,
          tooltip: 'Goto Next',
          child: Icon(Icons.update),
        ),
      ),
    );
  }

  /**
   * 這裡定義一個native方法,用於開啟一個新的activity,這個activity是一個dialog模式的,意味著會呼叫當前
   * activity的 onPause,但是不會呼叫onStop
   */
  void _updateText() async{
    await platform.invokeMethod("gotoNext");
  }
}

void main() {
  runApp(MyApp());
}

    

  native生命週期 flutter生命週期
開啟app onCreate->onStart->onResume
開啟dialog actiivty onPause AppLifecycleState.inactive
關閉 dialog actiivty onResume AppLifecycleState.resumed
home onPause->onStop AppLifecycleState.inactive -> AppLifecycleState.paused
返回app onStart->onResume AppLifecycleState.inactive -> AppLifecycleState.resumed
返回鍵退出 onPause->onStop->onDestory AppLifecycleState.inactive -> AppLifecycleState.paused

    

    先看看Flutter有哪幾種狀態 (這個地方就非常困惑了,因為官方文件上寫的和我實際測試的存在區別,基於不迷信書本的理念,我實事求是貼出觀測情況,有錯誤還請大家指正下)

    AppLifecycleState.inactive  應用處於非活動狀態,並且沒有接收到使用者輸入。在Android中,這對應應用在前臺非活動狀態,比如分屏應用,電話,畫中畫應用,系統對話方塊或者其他視窗。類似於onPause,但是又不完全是,因為在返回app的時候也會先進入inactive狀態,然後再resumed。

    AppLifecycleState.paused 當應用對於使用者不可見,不響應輸入,並且在後臺執行。相當於android中的onStop 。處於這個狀態的app隨時都會進入suspending掛起狀態。

    AppLifecycleState.resumed 相當於android中的onPostResume(onResume之後執行),表示應用可見並且響應輸入.

    AppLifecycleState.suspending 應用處於掛起狀態。暫時還沒有見到這種狀態。

如何在一個widget上新增onClick事件    

    在Flutter中有兩個方式來新增點選事件:

    1.如果widget本身支援事件分發,比如RaisedButton,它有一個onPressed引數,這種情況我們可以直接使用

@override
Widget build(BuildContext context) {
  return RaisedButton(
      onPressed: () {
        print("click");
      },
      child: Text("Button"));
}

    2.如果widget本身不支援事件分發,那麼就需要把這個控制元件包裹在一個GestureDetector控制元件中,並且響應onTab引數。

class SampleApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: Center(
      child: GestureDetector(
        child: FlutterLogo(
          size: 200.0,
        ),
        onTap: () {
          print("tap");
        },
      ),
    ));
  }
}

 

響應其他手勢事件

    實際上我們已經在前面簽名版的時候監聽過一些手勢事件了,這裡列舉一下GestureDetector能夠響應的事件

    點選:

            onTabDown -> 類似於ACTION_DOWN

            onTabUp ->  ACTION_UP

            onTab -> 點選事件

            onTabCancel ->點選被取消,觸發了onTabDown,但是不會觸發onTabUp 和 onTab

    雙擊:

            onDoubleTab

    長按

            onLongPress

    垂直拖動

            onVerticalDragStart  和螢幕接觸,並且可能會開始垂直的移動

            onVerticalDragUpdate  和螢幕接觸,在垂直方向上進一步移動

            onVerticalDragEnd 之前與螢幕接觸的指標不再於螢幕接觸,並且在停止接觸時有一個移動速度

    水平拖動

            onHorizontalDragStart

            onHorizontalDragUpdate

            onHorizontalDragEnd

匯入三方字型

    我們可以到Google Fonts下載各種字型

    首先我們需要先準備好我們的字型檔案ttf,並且將其放入Flutter app下面,比如放在fonts資料夾中

awesome_app/
  fonts/
    Raleway-Regular.ttf
    Raleway-Italic.ttf
    RobotoMono-Regular.ttf
    RobotoMono-Bold.ttf

    和android中直接載入字型到textview中不同,我們需要在pubspec.yaml檔案中註冊我們的字型.

  fonts:
    - family: Raleway
          fonts:
            - asset: fonts/Raleway-Regular.ttf
            - asset: fonts/Raleway-Italic.ttf
              style: italic
    - family: RobotoMono
          fonts:
            - asset: fonts/RobotoMono-Regular.ttf
            - asset: fonts/RobotoMono-Bold.ttf
              weight: 700

    family表示字型的名字,我們在TextStyle物件(用於確定字型樣式的物件)的fontFamily中填入family值來使用這個字型。

    asset指向字型檔案的地址。在打包時這些字型檔案會被打包到應用程式中。

    同一種字型可以有不同的輪廓。

        weight 用來用來表示字型的粗細,值在100到900之間,是100的整數倍。我們可以在TextStyle的fontWeight中設定這個值。

        style 表示字型是斜體還是正常,可以在TextStyle的fontStyle中指定。

    我們刻通過在主題中設定fontFamily來改變預設字型,當然也可以在單獨的控制元件中使用

MaterialApp(
  title: 'Custom Fonts',
  // Set Raleway as the default app font
  theme: ThemeData(fontFamily: 'Raleway'),
  home: MyHomePage(),
);

    或者

Text(
  'Roboto Mono sample',
  style: TextStyle(fontFamily: 'RobotoMono'),
);

    如果我們給TextStyle設定的weight或者style沒有對應的asset,那麼系統就會自動選擇這種字型裡的一種風格。

 

如何在Flutter中使用NDK

    很遺憾,當前在Flutter中沒有辦法直接呼叫c++的程式碼,所有c++程式碼都需要經過native層的中轉,建立custom plugin或者直接MethodChannel。

如何使用Shared Preferences

    Shared_Preferences plugin

    這是一個Flutter外掛,能夠在NSUserDefaults(ios中的資料儲存)和Shared Preferences的功能.

如何使用SQLite

    SQFlite

如何使用訊息推送

    這個目前Flutter對於Firebase還是有外掛的,但是其他的三方推送就沒有外掛了,只能自己開發或者建立Channel

結語

    至此,我們已經入門了Flutter,隨著學習的深入,發現Flutter並不是一個簡單的UI替代方案,它已經是一整套完整的開發流程。另外最近Flutter的火熱程度感覺急速上升,或許真能在移動開發界掀起顛覆也說不定。另外,據說Flutter也在向其他平臺進軍,它的目標是整合所有前端開發(PC應用,網頁前端等等)。並且在2019年的I/O大會上還會有更多的分享。