ScrollView 是一個帶有滾動的視圖組件。
目前創新互聯公司已為成百上千家的企業提供了網站建設、域名、網頁空間、網站運營、企業網站設計、開平網站維護等服務,公司將堅持客戶導向、應用為本的策略,正道將秉承"和諧、參與、激情"的文化,與客戶和合作伙伴齊心協力一起成長,共同發展。
ScrollView 由三部分組成:
ScrollView 有以下常用屬性:
注:ScrollView 是一個抽象類,通常使用 CustomScrollView。
SliverAppBar 可以實現背景,標題,頂部導航欄聯動,漸隱漸出動畫。
騰訊課堂14M
今日頭條3M
閑魚22M
百度貼吧13M
螞蟻財富56.8M
百度網盤14M
手機淘寶15M
貝殼找房8M
由粗粒度小組件動態拼裝出頁面,Native端已經有很多成熟的框架,如天貓的Tangram。
開發語言:iOS、Android
適用場景:快速迭代的活動營銷頁面
優點:無侵入,更新簡單
缺點:提前預埋,擴展性差,靈活性差
以webview作為容器的app,歷史悠久,最早到2011年。
開發語言:HTML
適用場景:雙端嚴格一致的銀行類app,容器類的支付寶小程序等
優點:動態更新,跨平臺
缺點:性能,加載速度
UI用Xml+JS表達,用Native View渲染。
開發語言:Xml+JS
適用場景:雙端嚴格一致的銀行類app,容器類的支付寶小程序等
優點:native組件,生態成熟
缺點:三方庫crash,性能缺陷
UI用Dart表達,用Dart engine渲染。
Flutter官方不支持動態化。原因是Flutter在 Release 模式下構建的是 AOT 編譯產物,在 Debug 模式下構建的是 JIT ,AOT 依賴的 Dart VM 和 JIT 并不一樣, JIT Release 并不支持 iOS 設備。可行的方案是:AOT 需要一個編譯后的 “Dart VM”。抽離一份 DartVM 獨立編譯,再以動態庫的形式引入項目。
開發語言:Dart
適用場景:iOS、Android、Web、Desktop、Embed
優點:性能最佳
缺點:增大包體積 20MB+
大廠的主流方案。UI用JS表達,用Dart engine渲染。
開發語言:JS、類JS
適用場景:iOS、Android
優點:性能最佳
缺點:需要掌握JS、Dart兩個語言和框架
大廠的主流方案。UI用Dart表達,用Dart engineX渲染。
開發語言:Dart
適用場景:iOS、Android
優點:性能最佳
缺點:需要改造Dart engine
1、 美團外賣Flutter動態化實踐
2、 攜程App 首頁動態化探索
3、 Flutter 動態化在最右 App 中的實踐
4、 Flutter 動態化熱更新的思考與實踐
5、 NOW直播Flutter動態搜索列表頁實現
6、 Flutter動態化的方案對比及最佳實現-閑魚
7、 基于JavaScript 的MXFlutter
Flutter中有兩個常用的狀態Widget分為StatefulWidget和StatelessWidget,分別為動態視圖和靜態視圖,視圖的更新需要調用StatefulWidget的setState方法,這會遍歷調用子Widget的build方法。如果一個頁面內容比較復雜時,會包含多個widget,如果直接調用setState,會遍歷所有子Widget的build,這樣會造成很多不必要的開銷,所以非常有必要了解Flutter中局部刷新的方式:
globalkey唯一定義了某個element,它使你能夠訪問與element相關聯的其他對象,例如buildContext、state等。應用場景:跨widget訪問狀態。
例如:可以通過key.currentState拿到它的狀態對象,然后就可以調用其中的onPressed方法。
Flutter框架內部提供了一個非常小巧精致的組件,專門用于局部組件的刷新。適用于值改動的刷新。
實現原理:在 initState 中對傳入的可監聽對象進行監聽,執行 _valueChanged 方法,_valueChanged 中進行了 setState 來觸發當前狀態的刷新。觸發 build 方法,從而觸發 widget.builder 回調,這樣就實現了局部刷新。可以看到這里回調的 child 是組件傳入的 child,所以直接使用,這就是對 child 的優化的根源。
可以看到 ValueListenableBuilder 實現局部刷新的本質,也是進行組件的抽離,讓組件狀態的改變框定在狀態內部,并通過 builder 回調控制局部刷新,暴露給用戶使用。
通過這個可以創建一個支持局部刷新的widget樹,比如你可以在StatelessWidget里面刷新某個布局,但是不需要改變成StatefulWidget;也可以在StatefulWidget中使用做部分刷新而不需要刷新整個頁面,這個刷新是不會調用Widget build(BuildContext context)刷新整個布局樹的。
異步UI更新:
很多時候我們會依賴一些異步數據來動態更新UI,比如在打開一個頁面時我們需要先從互聯網上獲取數據,在獲取數據的過程中顯示一個加載框,等獲取到數據時我們再渲染頁面;又比如我們想展示Stream(比如文件流、互聯網數據接收流)的進度。當然StatefulWidget我們完全可以實現以上功能。但由于在實際開發中依賴異步數據更新UI的這種場景非常常見,并且當StatefulWidget中控件樹較大時,更新一個屬性導致整個樹重建,消耗性能,因此Flutter專門提供了FutureBuilder和SteamBuilder兩個組件來快速實現這種功能。
通常情況下,子Widget無法單獨感知父Widget的變化,當父state變化時,通過其build重建所有子widget;
InheriteddWidget可以避免這種全局創建,實現局部子Widget更新。InheritedWidget提供了一種在Widget樹中從上到下傳遞、共享數據的方式。Flutter SDK正是通過InheritedWidget來共享應用主題和Locale等信息。
InheritedWidgetData
TestData
InheritedTest1Page
provider是Google I/O 2019大會上宣布的現在官方推薦的管理方式,而ChangeNotifierProvider可以說是Provider的一種:
yaml文件需要引入provider: ^3.1.0
頂層嵌套ChangeNotifierProvider
創建共享數據類DataInfo:
數據類需要with ChangeNotifier 以使用 notifyListeners()函數通知監聽者更新界面。
使用Provider.of(context)獲取DataInfo
nextPage:
使用Consumer包住需要使用共享數據的Widget
RepaintBoundary就是重繪邊界,用于重繪時獨立于父視圖。頁面需要更新的頁面結構可以用 RepaintBoundary組件嵌套,flutter 會將包含的組件獨立出一層"畫布",去繪制。官方很多組件 外層也包了層 RepaintBoundary 標簽。如果你的自定義view比較復雜,應該盡可能的避免重繪。
以上總結了幾種Flutter的局部刷新的方式,可根據實際需要使用不同的方式,最適合的才是最好的。
Flutter中Widget分為StatefulWidget和StatelessWidget,分別為動態視圖和靜態視圖,視圖的更新需要調用StatefulWidget的setState方法,這會遍歷調用子Widget的build方法。當一個主頁面比較復雜時,會包含多個widget,如果直接調用setState,會遍歷所有子Widget的build,這是非常不必要的性能開銷,有沒有單獨刷新指定Widget的方式呢?這個時候就要用到GlobalKey了。
一個StatefulWidget包含一個Button,一個Text,通過點擊Button調用主Widget的setState方法,刷新Text,示例如下:
同樣一個StatefulWidget包含一個多個Text和Button,點擊Button我們只需要刷新指定的Text,通過GlobalKey的方式,實現如下:
主Widget,包含一個需要更新的TextWidget和一個不需要更新的Text
需要單獨更新的Widget
傳遞事件的Button
這樣點擊Button就只會更新指定的TextWidget了,效果如下:
這只是一個簡單的例子,在實際開發中為了頁面刷新的高效率,模塊化封裝非常重要。很多情況下都只需要局部刷新,而不是重構整個視圖。所以Globalkey的運用在項目中需要熟練掌握