做爲系列文章的第八篇,本篇是主要講述 Flutter 開發過程當中的實用技巧,讓你少走彎路少掉坑,全篇屬於很乾的乾貨總結,以實用爲主,算是在深刻原理過程當中穿插的實用篇章。android
前文:git
有時候咱們爲 Text
設置 ellipsis ,卻發現並無生效,而是出現以下圖左邊提示 overflowed
的警告。github
其實大部分時候,這是 Text
內部的 RenderParagraph
在判斷 final bool didOverflowWidth = size.width < textSize.width;
時, size.width 和 textSize.width 是相等致使的。安全
因此你須要給 Text
設置一個 Container
之類的去約束它的大小,或者是 Row
中經過 Expanded
+ Container
去約束你的 Text
。bash
看過第六篇的同窗應該知道, 咱們能夠用 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));
}
複製代碼
若是你看過 MaterialApp
的源碼,你應該會看到它的內部是一個 WidgetsApp
,而 WidgetsApp
內有一個 MediaQuery
,熟悉它的朋友知道咱們能夠經過 MediaQuery.of(context).size
去獲取屏幕大小。async
其實 MediaQuery
是一個 InheritedWidget
,它有一個叫 MediaQueryData
的參數,這個參數是經過以下圖設置的,再經過源碼咱們知道,通常狀況下 MediaQueryData
的 padding
的 top
就是狀態欄的高度。佈局
因此咱們能夠經過 MediaQueryData.fromWindow(WidgetsBinding.instance.window).padding.top
獲取到狀態欄高度,固然有時候可能須要考慮 viewInsets
參數。post
至於 AppBar
的高度,默認是 Size.fromHeight(kToolbarHeight + (bottom?.preferredSize?.height ?? 0.0)),
,kToolbarHeight 是一個固定數據,固然你能夠經過實現 PreferredSizeWidget
去自定義 AppBar
。字體
同時你可能會發現,有時候在佈局時發現佈局位置不正常,竟然是從狀態欄開始計算,這時候你須要用 SafeArea
嵌套下,至於爲何,看源碼你就會發現 MediaQueryData
的存在。
簡單的能夠經過 AppBar
的 brightness 或者 ThemeData
去設置狀態欄顏色。
可是若是你不想用 AppBar
,那麼你能夠嵌套 AnnotatedRegion<SystemUiOverlayStyle>
去設置狀態欄樣式,經過 SystemUiOverlayStyle
就能夠快速設置狀態欄和底部導航欄的樣式。
同時你還能夠經過 SystemChrome.setSystemUIOverlayStyle
去設置,前提是你沒有使用 AppBar
。須要注意的是,全部狀態欄設置是全局的, 若是你在 A 頁面設置後,B 頁面沒有手動設置或者使用 AppBar ,那麼這個設置將直接呈如今 B 頁面。
如今的手機通常都提供字體縮放,這給應用開發的適配上帶來必定工做量,因此大多數時候咱們會選擇禁止應用跟隨系統字體縮放。
在 Flutter 中字體縮放也是和 MediaQueryData
的 textScaleFactor
有關。因此咱們能夠在須要的頁面,經過最外層嵌套以下代碼設置,將字體設置爲默認不容許縮放。
MediaQuery(
data: MediaQueryData.fromWindow(WidgetsBinding.instance.window).copyWith(textScaleFactor: 1),
child: new Container(),
);
複製代碼
在使用 Container
的時候咱們常常會使用到 margin 和 padding 參數,其實在上一篇咱們已經說過, Container
其實只是對各類佈局的封裝,內部的 margin 和 padding 實際上是經過 Padding
實現的,而 Padding
不支持負數,因此若是你須要用到負數的狀況下,推薦使用 Transform
。
Transform(
transform: Matrix4.translationValues(10, -10, 0),
child: new Container(),
);
複製代碼
平常開發中咱們大體上會使用兩種圓角方案:
Decoration
的實現類 BoxDecoration
去實現。ClipRRect
去實現。其中 BoxDecoration
通常應用在 DecoratedBox
、 Container
等控件,這種實現通常都是直接 Canvas 繪製時,針對當前控件的進行背景圓角化,並不會影響其 child 。這意味着若是你的 child 是圖片或者也有背景色,那麼極可能圓角效果就消失了。
而 ClipRRect
的效果就是會影響 child 的,具體看看其以下的 RenderObject 源碼可知。
若是你在使用 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)
)
複製代碼
Flutter 中經過 FutureBuilder
或者 StreamBuilder
能夠和簡單的實現懶加載,經過 future
或者 stream
「異步」 獲取數據,以後經過 AsyncSnapshot
的 data 再去加載數據,至於流和異步的概念,之後再展開吧。
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);
複製代碼
自此,第八篇終於結束了!(///▽///)
《Flutter完整開發實戰詳解(1、Dart語言和Flutter基礎)》
《Flutter完整開發實戰詳解(4、Redux、主題、國際化)》
《Flutter完整開發實戰詳解(6、 深刻Widget原理)》
《Flutter完整開發實戰詳解(10、 深刻圖片加載流程)》
《Flutter完整開發實戰詳解(11、全面深刻理解Stream)》
《React Native 的將來與React Hooks》