Flutter實戰之開發問題集(一)

問題集每篇記錄設置在十個左右。絕大多數都是本身在Flutter實際開發中遇到的狀況和解決辦法,加深在開發過程當中面對問題的思考和思路以及往後方便查閱作備份同時也但願能爲你們帶來幫助。html

Flutter中文字和英文字高度顯示不一樣

這就存在一個問題,在UI佈局若是爲Text設置Padding的時候會出現中英文文本顯示高度不一致的狀況。難怪設計師總是找我茬,總算知道問題所在了。 android

解決辦法其實很簡單在TextStyle中將height設爲1就能能夠了。

TextStyle(
    fontSize: 15,
    fontFamily: "",
    height: 1,
)
複製代碼

實際中會發現中文顯示會超出實際高度,但這裏咱們是爲了保持統一高度以便於對外邊框作設置,因此超出部分並不影響正常使用。 ios

滑動組件在Android和iOS不一樣表現

因爲Android和iOS平臺UI規範不一樣致使滑動組件交互性存在差別。例如在Android平臺在邊界是波紋動畫交互而iOS平臺邊界是回彈阻尼效果。所開發者但願統一交互效果可用ClampingScrollPhysics(Android)或是BouncingScrollPhysics(iOS)二者替換SingleChildScrollView的physics。git

SingleChildScrollView(
    physics: BouncingScrollPhysics(), ///ClampingScrollPhysics
)
複製代碼

設計師請不要切這麼多Icon

Android的ImageView有個屬性爲tint能夠渲染圖片顏色,但前提是渲染的圖片爲單色。那麼在Flutter中Iamge的color也是一樣的做用,一方面能夠減小切圖量一方面方便開發後期調色。以前一些Icon在可點擊和不可點擊呈現顏色是不一樣,UI在切圖上是一樣圖片切了兩份給我,因爲切圖非單色致使渲染圖片顏色失敗。github

Image.asset(
   "res/drawable/ic_circle_company.png",
   height: 40,
   width: 40,
   color:Colors.red,
),
複製代碼

單色切圖能夠經過設置不一樣顏色實現顏色替換,因此有狀態的圖標儘可能讓設計師切成單色剩下交給開發者自由發揮。 redux

雖然這不算是真正的開發問題,但也算是開發過程當中遇到的有意義的問題因此仍是想記錄一下,對於重複和可優化的點咱們是否是應該儘可能最簡化呢。另外減小冗餘資源佔用下降應用包大小。bash

關於路由不要只會用pop了

timer = Timer.periodic(Duration(milliseconds: 100), (timer) {
  if (num == 0) {
    timer.cancel();
    Navigator.of(context).pop();
    bus.emit(EventBus.privateEvent);
  } else {
    num--;
    setState(() {});
  }
});
複製代碼

如上代碼閃屏頁倒計時關閉邏輯,由於還存在其餘異步的業務邏輯好比在閃屏頁面出現登陸退出彈出登陸頁面。而後倒計時結束調用Navigator.of(context).pop時退出的是路由棧最上登陸頁,致使路由棧頁面出現問題沒法手動退出閃屏頁同時進入不到首頁(預先閃屏頁已經設置了禁止退出)。所以使用removeRoute用於關閉當前頁面。markdown

瞭解更多關於Flutter路由能夠看看Flutter實戰之路由功能篇網絡

timer = Timer.periodic(Duration(milliseconds: 100), (timer) {
  if (num == 0) {
    timer.cancel();
    Navigator.of(context).removeRoute(ModalRoute.of(context));
    bus.emit(EventBus.privateEvent);
  } else {
    num--;
    setState(() {});
  }
});
複製代碼

TextField使用真要命

在特殊狀況下使用TextField問題,例如在Row嵌套TextField要有Expanded約束寬度。app

展現佈局失敗

一些特殊狀況會致使佈局構建失敗,例如使用外層加入Row包裝時會報錯。

Row(
  children: <Widget>[
    Image.asset("res/img/ic_star.png"),
    TextField(
        cursorColor: Colors.grey,
        decoration: InputDecoration(
          hintText: "HHHHHH",
          border: InputBorder.none,
          contentPadding: EdgeInsets.all(0),
          isDense: true,
        ),
      ),
  ],
)
複製代碼

An InputDecorator, which is typically created by a TextField, cannot have an unbounded width 這時只能在TextField外層嵌套Expanded解決。

Row(
  children: <Widget>[
    Image.asset("res/img/ic_star.png"),
    Expanded(
      child: TextField(
        cursorColor: Colors.grey,
        decoration: InputDecoration(
          hintText: "HHHHHH",
          border: InputBorder.none,
          contentPadding: EdgeInsets.all(0),
          isDense: true,
        ),
      ),
    ),
  ],
)
複製代碼

獲取焦點彈起軟鍵盤

一般狀況輸入框默認獲取焦點彈起軟鍵盤的方式。

TextField(
  autofocus: true,
)
複製代碼

但也存在輸入框焦點默認仍是未獲取軟鍵盤沒彈出的狀況,那麼再經過設置focusNode實現。

SchedulerBinding.instance.addPostFrameCallback((_) {
   FocusScope.of(context).requestFocus(_focusNode);
});
TextField(
   autofocus: true,
   focusNode: _focusNode,
)
複製代碼

最後在退出頁面時記得焦點移除收回軟鍵盤

FocusScope.of(context).requestFocus(FocusNode());
複製代碼

輸入框與其餘組件顯示高度問題

由於原生輸入框樣式並不知足平常業務開發並自定義輸入框採用了Container嵌套輸入框增長外邊框樣式。以下代碼致使輸入框和其餘組件高度再也不統一水平線上。

Container(
  margin: EdgeInsets.symmetric(horizontal: 10),
  padding: EdgeInsets.symmetric(horizontal: 10),
  alignment: Alignment.centerLeft,
  height: 30,
  decoration: new BoxDecoration(
    color: Colors.blueGrey,
    borderRadius: new BorderRadius.circular(4),
  ),
  child: Row(
    crossAxisAlignment: CrossAxisAlignment.center,
    children: <Widget>[
      Image.asset(
        "res/img/ic_star.png",
        width: 10,
      ),
      Expanded(
        child: TextField(
          cursorColor: Colors.grey,
          autofocus: true,
          decoration: InputDecoration(
              hintText: "HHHHHH",
          ),
          showCursor: true,
          textInputAction: TextInputAction.search,
        ),
      ),
    ],
  ),
),
複製代碼

最後設置以下代碼解決,isDense爲true、contentPadding都設爲0。

TextField(
  cursorColor: Colors.grey,
  decoration: InputDecoration(
      hintText: "HHHHHH",
      border: InputBorder.none,
      contentPadding: EdgeInsets.all(0),
      isDense: true,
      hintStyle: TextStyle(fontSize: 15)),
  style: TextStyle(fontSize: 15),
  showCursor: true,
),
複製代碼

Flutter網絡請求沒法抓包狀況

測試同窗說我開發應用沒法抓包,想對測試數據進行監控和問題排查帶來困惑。事實上是Flutter開發中網絡請求默認沒法直接抓包。

Flutter升級到V1.12.3 iOS包大小問題

以前開發一直使用FlutterV1.9的版本,由於FlutterBoost有升級到支持V1.12.3-hotfix因此想做死一把將Flutter更新上去。前期升級很順利沒遇到啥問題基本上無任何須要修改配置的地方,直到在進行iOS打包時問題發生了。原先iOS打包後包大小在30M左右,如今包大小在100M左右。

確認再三我打包爲release版本後趕忙在github上看issue,果然遇到這個問題的人不僅我一個。該問題不是Flutter的bug而是1.12版本開始Flutter引擎包含了LLVM IR (bitcode)致使包大小發生變化。

同時將ios打包的ipa文件上傳到App Store Connect後平臺會自動將安裝包壓縮至正常大小。但目前還不瞭解如何作到不上傳到store也把包大小壓縮下來,後期有時間再研究研究。

頁面路由返回值處理

頁面返回除了appbar的返回鍵外還有側滑操做。在側滑操做返回經過路由傳遞參數一樣須要攔截側滑返回操做自定義路由彈出操做傳遞須要的參數。這裏就用到WillPopScope組件將onWillPop返回值設爲Future.value(false),而後自定義設置回參值。所以如有業務需求都須要返回值時則要特別注意這一點。但你若是使用了redux全局狀態管理估計能夠忽略這個問題了😂

但從另外一方面來看經過路由方式傳參並非特別酸爽,一些特殊狀況下還須要考慮多種狀況。或許全局狀態管理確實是另外一種更好的選擇。

PS: 同時WillPopScope也適用於loading加載時禁止側滑退出等操做

onWillPop: () {
    Navigator.of(context).pop({
      "code": industryCode,
      "filter": vm.filters.length > 0 ? vm.filters : "",
    });
    return Future.value(false);
  },
複製代碼

iPhoneX底部黑棒棒適配

底部導航欄默認支持iOS底部橫條的適配,但本身寫的佈局就可能存在問題啦。例如使用Stack在底部Position組件頗有可能組件顯示內容被橫條擋住。

Scaffold(
  appBar: AppBar(),
  body: Container(
    color: Colors.green,
    child: Stack(
      children: <Widget>[
        Positioned(
          bottom: 0,
          child: Text("LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL"),
        )
      ],
    ),
  ),
);
複製代碼

查看BottomNavigationBar源碼會發現下面一段代碼,經過MediaQuery.of(context).padding獲取屏幕底部內邊距,在BottomNav佈局中設置Padding來避免被橫條遮擋。

// Labels apply up to _bottomMargin padding. Remainder is media padding.
    final double additionalBottomPadding = math.max(MediaQuery.of(context).padding.bottom - widget.selectedFontSize / 2.0, 0.0);
/// 省略了部分無用代碼 
.... 
Padding(
  padding: EdgeInsets.only(bottom: additionalBottomPadding),
  child: MediaQuery.removePadding(
    context: context,
    removeBottom: true,
    child: _createContainer(_createTiles()),
  ),
 ),
複製代碼

所以對ios橫條適配須要對距底部的組件在加上MediaQuery.of(context).padding.bottom間距。固然對於iPhoneX的bottom值才大於0,像iPhone6獲取到的bottom值則爲0以及android也是如此(具體狀況看手機型號和機型而定)。

相關文章
相關標籤/搜索