Flutter完整開發實戰詳解(8、 實用技巧與填坑)

做爲系列文章的第八篇,本篇是主要講述 Flutter 開發過程當中的實用技巧,讓你少走彎路少掉坑,全篇屬於很乾的乾貨總結,以實用爲主,算是在深刻原理過程當中穿插的實用篇章。android

前文:git

一、Text 的 TextOverflow.ellipsis 不生效

有時候咱們爲 Text 設置 ellipsis ,卻發現並無生效,而是出現以下圖左邊提示 overflowed 的警告。github

其實大部分時候,這是 Text 內部的 RenderParagraph 在判斷 final bool didOverflowWidth = size.width < textSize.width; 時, size.widthtextSize.width 是相等致使的。安全

因此你須要給 Text 設置一個 Container 之類的去約束它的大小,或者是 Row 中經過 Expanded + Container 去約束你的 Textbash

請無視圖片

二、獲取控件的大小和位置

看過第六篇的同窗應該知道, 咱們能夠用 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 的參數,這個參數是經過以下圖設置的,再經過源碼咱們知道,通常狀況下 MediaQueryDatapaddingtop 就是狀態欄的高度。佈局

因此咱們能夠經過 MediaQueryData.fromWindow(WidgetsBinding.instance.window).padding.top 獲取到狀態欄高度,固然有時候可能須要考慮 viewInsets 參數。post

至於 AppBar 的高度,默認是 Size.fromHeight(kToolbarHeight + (bottom?.preferredSize?.height ?? 0.0)),kToolbarHeight 是一個固定數據,固然你能夠經過實現 PreferredSizeWidget 去自定義 AppBar字體

同時你可能會發現,有時候在佈局時發現佈局位置不正常,竟然是從狀態欄開始計算,這時候你須要用 SafeArea 嵌套下,至於爲何,看源碼你就會發現 MediaQueryData 的存在。

四、設置狀態欄顏色和圖標顏色

簡單的能夠經過 AppBarbrightness 或者 ThemeData 去設置狀態欄顏色。

可是若是你不想用 AppBar ,那麼你能夠嵌套 AnnotatedRegion<SystemUiOverlayStyle> 去設置狀態欄樣式,經過 SystemUiOverlayStyle 就能夠快速設置狀態欄和底部導航欄的樣式。

同時你還能夠經過 SystemChrome.setSystemUIOverlayStyle 去設置,前提是你沒有使用 AppBar須要注意的是,全部狀態欄設置是全局的, 若是你在 A 頁面設置後,B 頁面沒有手動設置或者使用 AppBar ,那麼這個設置將直接呈如今 B 頁面。

五、系統字體縮放

如今的手機通常都提供字體縮放,這給應用開發的適配上帶來必定工做量,因此大多數時候咱們會選擇禁止應用跟隨系統字體縮放。

在 Flutter 中字體縮放也是和 MediaQueryDatatextScaleFactor 有關。因此咱們能夠在須要的頁面,經過最外層嵌套以下代碼設置,將字體設置爲默認不容許縮放。

MediaQuery(
      data: MediaQueryData.fromWindow(WidgetsBinding.instance.window).copyWith(textScaleFactor: 1),
      child: new Container(),
    );
複製代碼

六、Margin 和 Padding

在使用 Container 的時候咱們常常會使用到 marginpadding 參數,其實在上一篇咱們已經說過, Container 其實只是對各類佈局的封裝,內部的 marginpadding 實際上是經過 Padding 實現的,而 Padding 不支持負數,因此若是你須要用到負數的狀況下,推薦使用 Transform

Transform(
      transform: Matrix4.translationValues(10, -10, 0),
      child: new Container(),
    );
複製代碼

七、控件圓角裁剪

平常開發中咱們大體上會使用兩種圓角方案:

  • 一種是經過 Decoration 的實現類 BoxDecoration 去實現。
  • 一種是經過 ClipRRect 去實現。

其中 BoxDecoration 通常應用在 DecoratedBoxContainer 等控件,這種實現通常都是直接 Canvas 繪製時,針對當前控件的進行背景圓角化,並不會影響其 child 。這意味着若是你的 child 是圖片或者也有背景色,那麼極可能圓角效果就消失了。

ClipRRect 的效果就是會影響 child 的,具體看看其以下的 RenderObject 源碼可知。

八、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)
    )
複製代碼

九、懶加載

Flutter 中經過 FutureBuilder 或者 StreamBuilder 能夠和簡單的實現懶加載,經過 future 或者 stream 「異步」 獲取數據,以後經過 AsyncSnapshot 的 data 再去加載數據,至於流和異步的概念,之後再展開吧。

十、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);
複製代碼

自此,第八篇終於結束了!(///▽///)

資源推薦

完整開源項目推薦:
文章

《Flutter完整開發實戰詳解(1、Dart語言和Flutter基礎)》

《Flutter完整開發實戰詳解(2、 快速開發實戰篇)》

《Flutter完整開發實戰詳解(3、 打包與填坑篇)》

《Flutter完整開發實戰詳解(4、Redux、主題、國際化)》

《Flutter完整開發實戰詳解(5、 深刻探索)》

《Flutter完整開發實戰詳解(6、 深刻Widget原理)》

《Flutter完整開發實戰詳解(7、 深刻佈局原理)》

《Flutter完整開發實戰詳解(8、 實用技巧與填坑)》

《Flutter完整開發實戰詳解(9、 深刻繪製原理)》

《Flutter完整開發實戰詳解(10、 深刻圖片加載流程)》

《Flutter完整開發實戰詳解(11、全面深刻理解Stream)》

《跨平臺項目開源項目推薦》

《移動端跨平臺開發的深度解析》

《React Native 的將來與React Hooks》

咱們還會再見嗎?
相關文章
相關標籤/搜索