一個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
這是一個Flutter外掛,能夠在NSUserDefaults(ios中的資料儲存)和Shared Preferences的功能.
如何使用SQLite
如何使用訊息推送
這個目前Flutter對於Firebase還是有外掛的,但是其他的三方推送就沒有外掛了,只能自己開發或者建立Channel
結語
至此,我們已經入門了Flutter,隨著學習的深入,發現Flutter並不是一個簡單的UI替代方案,它已經是一整套完整的開發流程。另外最近Flutter的火熱程度感覺急速上升,或許真能在移動開發界掀起顛覆也說不定。另外,據說Flutter也在向其他平臺進軍,它的目標是整合所有前端開發(PC應用,網頁前端等等)。並且在2019年的I/O大會上還會有更多的分享。