作為系列文章的第八篇,本篇是主要講述 Flutter 開發過程中的實用技巧,讓你少走彎路少掉坑,全篇屬於很乾的乾貨總結,以實用為主,算是在深入原理過程中穿插的實用篇章。
前文:
1、Text 的 TextOverflow.ellipsis 不生效
有時候我們為 Text
設定 ellipsis ,卻發現並沒有生效,而是出現如下圖左邊提示 overflowed
的警告。
其實大部分時候,這是 Text
內部的 RenderParagraph
在判斷 final bool didOverflowWidth = size.width < textSize.width;
時, size.width 和 textSize.width 是相等導致的。
所以你需要給 Text
設定一個 Container
之類的去約束它的大小,或者是 Row
中通過 Expanded
+ Container
去約束你的 Text
。
2、獲取控制元件的大小和位置
看過第六篇的同學應該知道, 我們可以用 GlobalKey
,通過 key 去獲取到控制元件物件的 BuildContext
,而前面我們也說過 BuildContext
的實現其實是 Element
,而 Element
持有 RenderObject
。So,我們知道的 RenderObject
,實際上獲取到的就是 RenderBox
,那麼通過 RenderBox 我們就只大小和位置了:
showSizes() {
RenderBox renderBoxRed = fileListKey.currentContext.findRenderObject();
print(renderBoxRed.size);
}
showPositions() {
RenderBox renderBoxRed = fileListKey.currentContext.findRenderObject();
print(renderBoxRed.localToGlobal(Offset.zero));
}
複製程式碼
3、獲取狀態列高度和安全佈局
如果你看過 MaterialApp
的原始碼,你應該會看到它的內部是一個 WidgetsApp
,而 WidgetsApp
內有一個 MediaQuery
,熟悉它的朋友知道我們可以通過 MediaQuery.of(context).size
去獲取螢幕大小。
其實 MediaQuery
是一個 InheritedWidget
,它有一個叫 MediaQueryData
的引數,這個引數是通過如下圖設定的,再通過原始碼我們知道,一般情況下 MediaQueryData
的 padding
的 top
就是狀態列的高度。
所以我們可以通過 MediaQueryData.fromWindow(WidgetsBinding.instance.window).padding.top
獲取到狀態列高度,當然有時候可能需要考慮 viewInsets
引數。
至於 AppBar
的高度,預設是 Size.fromHeight(kToolbarHeight + (bottom?.preferredSize?.height ?? 0.0)),
,kToolbarHeight 是一個固定資料,當然你可以通過實現 PreferredSizeWidget
去自定義 AppBar
。
同時你可能會發現,有時候在佈局時發現佈局位置不正常,居然是從狀態列開始計算,這時候你需要用 SafeArea
巢狀下,至於為什麼,看原始碼你就會發現 MediaQueryData
的存在。
4、設定狀態列顏色和圖示顏色
簡單的可以通過 AppBar
的 brightness 或者 ThemeData
去設定狀態列顏色。
但是如果你不想用 AppBar
,那麼你可以巢狀 AnnotatedRegion<SystemUiOverlayStyle>
去設定狀態列樣式,通過 SystemUiOverlayStyle
就可以快速設定狀態列和底部導航欄的樣式。
同時你還可以通過 SystemChrome.setSystemUIOverlayStyle
去設定,前提是你沒有使用 AppBar
。需要注意的是,所有狀態列設定是全域性的, 如果你在 A 頁面設定後,B 頁面沒有手動設定或者使用 AppBar ,那麼這個設定將直接呈現在 B 頁面。
5、系統字型縮放
現在的手機一般都提供字型縮放,這給應用開發的適配上帶來一定工作量,所以大多數時候我們會選擇禁止應用跟隨系統字型縮放。
在 Flutter 中字型縮放也是和 MediaQueryData
的 textScaleFactor
有關。所以我們可以在需要的頁面,通過最外層巢狀如下程式碼設定,將字型設定為預設不允許縮放。
MediaQuery(
data: MediaQueryData.fromWindow(WidgetsBinding.instance.window).copyWith(textScaleFactor: 1),
child: new Container(),
);
複製程式碼
6、Margin 和 Padding
在使用 Container
的時候我們經常會使用到 margin 和 padding 引數,其實在上一篇我們已經說過, Container
其實只是對各種佈局的封裝,內部的 margin 和 padding 其實是通過 Padding
實現的,而 Padding
不支援負數,所以如果你需要用到負數的情況下,推薦使用 Transform
。
Transform(
transform: Matrix4.translationValues(10, -10, 0),
child: new Container(),
);
複製程式碼
7、控制元件圓角裁剪
日常開發中我們大致上會使用兩種圓角方案:
- 一種是通過
Decoration
的實現類BoxDecoration
去實現。 - 一種是通過
ClipRRect
去實現。
其中 BoxDecoration
一般應用在 DecoratedBox
、 Container
等控制元件,這種實現一般都是直接 Canvas 繪製時,針對當前控制元件的進行背景圓角化,並不會影響其 child 。這意味著如果你的 child 是圖片或者也有背景色,那麼很可能圓角效果就消失了。
而 ClipRRect
的效果就是會影響 child 的,具體看看其如下的 RenderObject 原始碼可知。
8、PageView
如果你在使用 TarBarView
,並且使用了 KeepAlive
的話,那麼我推薦你直接使用 PageView
。因為目前到 1.2 的版本,在 KeepAlive
的 狀態下,跨兩個頁面以上的 Tab 直接切換, TarBarView
會導致頁面的 dispose
再重新 initState
。儘管 TarBarView
內也是封裝了 PageView
+ TabBar
。
你可以直接使用 PageView
+ TabBar
去實現,然後 tab 切換時使用 _pageController.jumpTo(MediaQuery.of(context).size.width * index);
可以避免一些問題。當然,這時候損失的就是動畫效果了。事實上 TarBarView
也只是針對 PageView
+ TabBar
做了一層封裝。
除了這個,其實還有第二種做法,使用如下方 PageStorageKey
保持頁面數狀態,但是因為它是 save and restore values ,所以的頁面的 dispose
再重新 initState
方法,每次都會被呼叫。
return new Scaffold(
key: new PageStorageKey<your value type>(your value)
)
複製程式碼
9、懶載入
Flutter 中通過 FutureBuilder
或者 StreamBuilder
可以和簡單的實現懶載入,通過 future
或者 stream
“非同步” 獲取資料,之後通過 AsyncSnapshot
的 data 再去載入資料,至於流和非同步的概念,以後再展開吧。
10、Android 返回鍵回到桌面
Flutter 官方已經為你提供了 android_intent 外掛了,這種情況下,實現回到桌面可以如下簡單實現:
Future<bool> _dialogExitApp(BuildContext context) async {
if (Platform.isAndroid) {
AndroidIntent intent = AndroidIntent(
action: 'android.intent.action.MAIN',
category: "android.intent.category.HOME",
);
await intent.launch();
}
return Future.value(false);
}
·····
return WillPopScope(
onWillPop: () {
return _dialogExitApp(context);
},
child:xxx);
複製程式碼
自此,第八篇終於結束了!(///▽///)
資源推薦
- Github : github.com/CarGuo
- 本文程式碼 :github.com/CarGuo/GSYG…
完整開源專案推薦:
文章
《Flutter完整開發實戰詳解(一、Dart語言和Flutter基礎)》
《Flutter完整開發實戰詳解(四、Redux、主題、國際化)》
《Flutter完整開發實戰詳解(六、 深入Widget原理)》
《Flutter完整開發實戰詳解(十、 深入圖片載入流程)》