Flutter-總結(jié)

簡介

谷歌開發(fā)的,有自己的渲染引擎,保持Android和iOS保持一致性
渲染方式自己渲染。

  • MaterialApp 類似AppDelegate 可以設(shè)置 主題樣式,home 首頁,路由routes,以及開發(fā)模式,debug or release
  • Scaffold [?sk?fo?ld] 腳手架 包含系統(tǒng)的一些UI組件,例如appBar、floatingActionButton、bottomNavigationBar
  • hot reload和hot restart 熱重載和熱重啟 如果修改了狀態(tài)相關(guān)的代碼則需要hot restart,否則只需要hot reload即可

布局

  • alignment 布局
  • Row 橫向排列 :主軸,交叉軸(X軸)
  • Column 縱向排列:主軸,交叉軸(Y軸)
  • Stack 層級排列,最大的在最下面(Z軸)
  • Expanded 自動填充:子部件隨著父部件的大小自己填充
  • column 布局 設(shè)置高度無意義
  • row 布局 設(shè)置寬度無意義

生命周期

  • 初始化
    • 構(gòu)造函數(shù) > initState > didChangeDependencies > Widget build
  • 狀態(tài)變化
    • 熱重載:reassemble > 組件狀態(tài)改變:didUpdateWidget > widget build
  • 組件移除
    • 頁面銷毀的時(shí)候會依次執(zhí)行:deactivate > dispose
  • 切至后臺
    • didChangeAppLifecycleState(AppLifecycleState.inactive) -> didChangeAppLifecycleState(AppLifecycleState.paused) -> build
  • 切回前臺
    • didChangeAppLifecycleState(AppLifecycleState.inactive) -> didChangeAppLifecycleState(AppLifecycleState.resumed) -> build

StatelessWidget - 生命周期

StatelessWidget 的生命周期只有一個,就是 build
build 是用來創(chuàng)建 Widget 的,但因?yàn)?build 在每次界面刷新的時(shí)候都會調(diào)用,所以不要在 build 里寫業(yè)務(wù)邏輯,可以把業(yè)務(wù)邏輯寫到你的 StatelessWidget 的構(gòu)造函數(shù)里。

class TestWidget extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    print('StatelessWidget build');
    return Text('Test');
  }
}

StatefulWidget - 生命周期

依次為

  • createState
  • initState
  • didChangeDependencies
  • build
  • addPostFrameCallback
  • didUpdateWidget
  • deactivate
  • dispose
有狀態(tài)生命周期

狀態(tài)管理

  • StatelessWidget(無狀態(tài))

一旦創(chuàng)建就不會發(fā)生變化,定義屬性值可以變化,但不會重新渲染UI,

  • StatefulWidget(有狀態(tài))
  • state發(fā)生變化時(shí)會重新渲染UI,類似于Hot Reload
  • 更新/刷新操作:setState(() {});
  • createState 此方法返回狀態(tài)管理類,進(jìn)行關(guān)聯(lián)

需要兩個類去管理

  • 描述UI
  • 記錄狀態(tài)的State (w,h)不銷毀,界面消失才會被干掉 : State屬性改變時(shí)會根據(jù)寬高重新渲染UI

頁面Push 和pop

Push

//push 跳轉(zhuǎn)新頁面
Navigator.of(context).push(
  MaterialPageRoute(builder: (BuildContext context){
     return DiscoverChildPage(title: this.title,);
  })

);

Pop

Navigator.pop(context);

Flutter混編

Channel

MethodChannel 傳遞方法 一次通訊

  • 1.通過setInitialRoute 向Flutter傳入?yún)?shù)
  • 2.Flutter接收傳入?yún)?shù)并顯示不同內(nèi)容 window.defaultRouteName
  • 3.setMethodCallHandler 判斷[call.method isEqualToString:@"picture"]

BasicMessageChannel 傳遞字符串

監(jiān)聽輸入框輸入文本 持續(xù)傳輸

EventChannel 傳遞數(shù)據(jù)流

常見問題

1.部件溢出

A RenderFlex overflowed by 22 pixels on the bottom.
//原因:在水平或者垂直方向上的內(nèi)容超過了父部件的大小

//解決辦法
包一層SingleChildScrollView,讓你的頁面可以滑動起來。
在Scaffold中設(shè)置resizeToAvoidBottomInset為false。默認(rèn)為ture,防止部件被遮擋。如果使用了這個方法,如果底部有輸入框,則會造成遮擋。

2.輸入框遮擋

Column配合Expanded來實(shí)現(xiàn)

3.SafeArea

一旦有部件固定在頂部或者底部(嚴(yán)謹(jǐn)點(diǎn)的話可以說是在屏幕的四邊)。那我我們最好使用SafeArea來包一下。因?yàn)锳ndroid 和 IOS都有狀態(tài)欄,甚至IOS還有叫做“HomeIndicator”的橫條。所以一不留神就會出現(xiàn)適配問題
使用方法為


Material( // 需要顏色填充到邊界區(qū)域可以使用
  color: Colors.white,
  child: SafeArea(
    child: Container(),
  ),
)

4.注意平臺差異

注意部分組件在Android與IOS平臺之間的差異。
ScaffoldAppBar,AppBar中默認(rèn)的title在Android中靠左顯示,IOS中居中顯示。如果需要兩個平臺效果統(tǒng)一,需要設(shè)置在AppBar中主動設(shè)置centerTitle屬性。同時(shí)AppBar的返回箭頭圖標(biāo)也不相同,統(tǒng)一的話需要自定義leading

頁面跳轉(zhuǎn)如果使用MaterialPageRoute來做過渡效果,注意Android中新的頁面會從屏幕底部滑動到屏幕頂部,IOS中新的頁面會從屏幕右側(cè)滑動到屏幕左側(cè)。

如果需要兩個平臺效果統(tǒng)一,我們不使用自帶效果,可以自定義一個

Navigator.push(context, PageRouteBuilder(transitionDuration: Duration(milliseconds: 300),
  pageBuilder: (context, animation, secondaryAnimation){
    return new FadeTransition( //使用漸隱漸入過渡,
      opacity: animation,
      child: TestPage(),
    );
  })
);

5.保持頁面狀態(tài)

比如點(diǎn)擊導(dǎo)航欄來回切換頁面,默認(rèn)情況下會丟失原頁面狀態(tài),也就是每次切換都會重新初始化頁面。這種情況解決方法就是PageViewBottomNavigationBar結(jié)合使用,同時(shí)子頁面State中繼承AutomaticKeepAliveClientMixin并重寫wantKeepAlive為true。代碼大致如下:


class _TestState extends State<Test> with AutomaticKeepAliveClientMixin{

  @override
  Widget build(BuildContext context) {
    super.build(context);
    return Container();
  }

  @override
  bool get wantKeepAlive => true;
}

6.依賴版本問題

首先這里建議凡是Flutter的插件在填寫版本號時(shí)不要使用^符號。

依賴版本問題

^符號意味著你可以使用此插件的最新版本(大于等于當(dāng)前版本)。這會導(dǎo)致什么問題呢?可能你前一天代碼還能跑起來,今天就編譯出錯了。因?yàn)檫@些插件中包括Android、IOS的所用依賴環(huán)境配置,常見的就是新版本使用了AndroidX的依賴,但是還有些插件并沒有使用AndroidX,導(dǎo)致了兩者的沖突。

7.常見第三方使用

7-1.Toast插件-oktoast

# Toast插件 https://github.com/OpenFlutter/flutter_oktoast
  oktoast: ^2.2.0
  
  import 'package:oktoast/oktoast.dart';
class Toast {
  static show(String msg, {duration = 2000}) {
    showToast(
        msg,
        duration: Duration(milliseconds: duration),
        dismissOtherToast: true
    );
  }
  static cancelToast() {
    dismissAllToast();
  }
}

7-1 圖片加載

# 圖片緩存 https://github.com/renefloor/flutter_cached_network_image
  cached_network_image: ^1.1.1
  /// 加載本地資源圖片
Widget loadAssetImage(String name, {double width, double height, BoxFit fit}){
  return Image.asset(
    Utils.getImgPath(name),
    height: height,
    width: width,
    fit: fit,
  );
}

/// 加載網(wǎng)絡(luò)圖片
Widget loadNetworkImage(String imageUrl, {String placeholder : "none", double width, double height, BoxFit fit: BoxFit.cover}){
  return CachedNetworkImage(
    imageUrl: imageUrl == null ? "" : imageUrl,
    placeholder: (context, url) => loadAssetImage(placeholder, height: height, width: width, fit: fit),
    errorWidget: (context, url, error) => loadAssetImage(placeholder, height: height, width: width, fit: fit),
    width: width,
    height: height,
    fit: fit,
  );
}

8.Redux 和 flutter_redux 詳解

  • Redux 是一種單向數(shù)據(jù)流,可以輕松開發(fā),維護(hù)和測試應(yīng)用程序,flutter_redux是用來簡化redux的使用
  • 在Redux中,所用的狀態(tài)都儲存在Store里,這個Store會放在App頂層
  • View拿到Store儲存的狀態(tài)并把它映射成視圖
  • Redux讓我們不能讓View直接操作數(shù)據(jù),而是通過發(fā)起一個action來告訴Reducer,狀態(tài)改變
  • 這時(shí)Reducer接收到了這個action,他就回去遍歷action 表然后找到匹配的action, 根據(jù)action生成新的狀態(tài)放在Store中
  • Store丟棄了老的狀態(tài)對象,儲存了新的狀態(tài)對象后,就通知所有使用到了這個狀態(tài)的View更新
  • ==能夠同步不同View種的狀態(tài)==

View 發(fā)起一個狀態(tài)改變的action-> Reducer(狀態(tài)生成器)找到匹配的action, 根據(jù)action生成新的狀態(tài)放在Store中 ->通知所有使用到了這個狀態(tài)的View更新,進(jìn)而同步不同View的狀態(tài)

使用

  • ①添加依賴
  • ②創(chuàng)建State @immutable
  • ③創(chuàng)建action
  • ④創(chuàng)建reducer : 狀態(tài)生成器,它接收一個我們原來的狀態(tài),然后接收一個action,再匹配這個action生成一個新的狀態(tài)
  • ⑤創(chuàng)建store : 將store儲存在應(yīng)用的入口,并初始化應(yīng)用狀態(tài)
  • ⑥將Store放入頂層 : StoreProvider,接收一個store,和child Widget
  • ⑦在子頁面中獲取Store中的state : StoreConnector能夠通過StoreProvider找到頂層的store。而且能夠在state發(fā)生變化時(shí)rebuilt Widget
同步不同View的狀態(tài)

補(bǔ)充

1.Flutter vs ReactNative 渲染機(jī)制

  • RN的效率由于是將View編譯成了原生View,效率比HTML5高很多,但它也有效率問題,RN的渲染機(jī)制是基于前端框架的考慮,復(fù)雜的UI渲染是需要依賴多個view疊加
  • Flutter在渲染技術(shù)上,選擇了自己實(shí)現(xiàn),直接通過 skia 渲染,有更好的可控性,使用了新的語言Dart,避免了RN的那種通過橋接器與Javascript通訊導(dǎo)致效率低下的問題,性能優(yōu)于RN.

ReactNative

  • 采用Javascript開發(fā),需學(xué)React,成本高
  • 需要JavaScript橋接器,實(shí)現(xiàn)JS到Native轉(zhuǎn)化,性能耗損
  • 訪問原生UI,頻繁操作易出性能問題
  • 支持線上動態(tài)性,可有效避免頻繁更新版本

Flutter

  • 采用Dart開發(fā),可直接編譯成Native代碼(易學(xué))
  • 自帶UI組件和渲染器,僅依賴系統(tǒng)提供的Canvas(無橋接耗損)
  • 暫不支持線上動態(tài)性,目前Android支持,ios不支持

2.setState方法是立即生效嗎?

setState 其實(shí)是調(diào)用了 markNeedsBuild ,該方法內(nèi)部標(biāo)記此Element 為 Dirty ,然后在下一幀 WidgetsBinding.drawFrame 才會被繪制,這可以看出 setState 并不是立即生效的

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容