發表日期:2018-07 文章編輯:小燈 瀏覽次數:2365
作者:閑魚技術-朝空
本文不是flutter界面開發入門文章,而是一篇深入介紹Flutter framework關于視圖樹的創建與管理機制、布局、渲染的原理、以及flutter布局與渲染相關性能優化的設計思路的文章。同時介紹在使用flutter開發過程中,遇到的一些坑和相應的解決方案。
本文主要介紹build、layout、paint的三個階段
flutter視圖樹包含了三種樹,上圖只是介紹了三顆樹的基礎class的對應關系和功能介紹
調用runApp(rootWidget),將rootWidget傳給rootElement,做為rootElement的子節點,生成Element樹,由Element樹生成Render樹
flutter界面開發是一種響應式編程,主張simple is fast,flutter設計的初衷希望數據變更時發送通知到對應的可變更節點(可能是一個StatefullWidget子節點,也可以是rootWidget),由上到下重新create widget樹進行刷新,這種思路比較簡單,不用關心數據變更會影響到哪些節點。
widget只是一個配置數據結構,創建是非常輕量的,加上flutter團隊對widget的創建/銷毀做了優化,不用擔心整個widget樹重新創建所帶來的性能問題,但是renderobject就不一樣了,renderobject涉及到layout、paint等復雜操作,是一個真正渲染的view,整個view 樹重新創建開銷就比較大,所以答案是否定的。
注意事項:
注意事項:
數據從根往下傳數據,常規做法是一層層往下,當深度變大,數據的傳輸變的困難,flutter提供InheritedWidget用于子節點向祖先節點獲取數據的機制,如下例子:
class FrogColor extends InheritedWidget {const FrogColor({Key key,@required this.color,@required Widget child,}) : assert(color != null), assert(child != null), super(key: key, child: child); final Color color; static FrogColor of(BuildContext context) {return context.inheritFromWidgetOfExactType(FrogColor);} @overridebool updateShouldNotify(FrogColor old) => color != old.color; }
child及其以下的節點可以通過調用下面的接口讀取color數據
FrogColor.of(context).color
說明:BuildContext 就是Element的一個接口類
imagecontext.inheritFromWidgetOfExactType(FrogColor)其實是通過context/element往上遍歷樹,查找到第一個FrogColor的祖先節點,取該節點的widget對象
子節點狀態變更,向上上報通過發送通知的方式
Notification(data).dispatch(context)
parent傳入約束條件,在dramframe的layout階段,child根據自身的渲染內容返回size
問題:在build()階段獲取不到size,很多時候需要提前知道部分widget size來進行布局,解決方案當widget 在對應renderobject的layout階段之后,發送一個LayoutChangeNotification,參考SizeChangedLayoutNotifier class,但是SizeChangedLayoutNotifier沒有上報init layout size,可以自己參考這個實現封裝一個Notifier
renderObject在layout階段做了Relayout boundary的優化,當子樹進行relayout時,滿足下面三種中的一種
那么該renderObject設置為Relayout boundary,也就是該renderObject的重新layout不觸發parent的layout,一般情況下開發人員不需要關心Relayout boundary,除非是使用CustomMultiChildLayout
iOS的每一個UIView都有一個layer,flutter的render object不一定存在layer,一般情況下一個renderObject子樹都渲染在一個layer上,那么什么renderObject具有layer,子renderObject怎么渲染到這個layer?
alwaysNeedsCompositing == true
或者isRepaintBoundary == true
,renderOject會有對應的compositing layer子renderObject會對目標layer返回對應的offsetLayer, 目標compositing layer再根據offset合成一個渲染的紋理buffer
類似Relayout boundary,Paint階段也有Repaint Boundary,目的和layout一樣,就是對應子樹的paint不會導致外部的repaint,但是Relayout boundary需要開發人員自己設置,使用RepaintBoundary widget進行設置,ListView在渲染的item默認都是使用了RepaintBoundary,顯而易見ListView的children之間都是相互獨立的。
Flutter建議復雜的image渲染使用RepaintBoundary,image的渲染需要io操作,然后解碼,最后渲染,使用RepaintBoundary可以進行gpu的緩存,但是不一定就會緩存,engine會判斷這個image是否足夠復雜,畢竟gpu緩存還是非常珍貴的,同時RepaintBoundary還會對一些反復渲染的layer進行緩存處理(反復渲染3次及以上,這個是flutter的視頻中提到的)
Flutter還處于Beta階段,有些界面編程的接口設計還不夠成熟,相比iOS和安卓生態還很不成熟,需要我們共同的創建,Flutter提供的調試工具相比一開始接觸的時候,已經完善很多,讓我們給Flutter更多的耐心和包容,期待Flutter越來越完善。
簡歷投遞:guicai.gxy@alibaba-inc.com
日期:2018-10 瀏覽次數:7248
日期:2018-12 瀏覽次數:4322
日期:2018-07 瀏覽次數:4870
日期:2018-12 瀏覽次數:4169
日期:2018-09 瀏覽次數:5492
日期:2018-12 瀏覽次數:9916
日期:2018-11 瀏覽次數:4799
日期:2018-07 瀏覽次數:4574
日期:2018-05 瀏覽次數:4853
日期:2018-12 瀏覽次數:4318
日期:2018-10 瀏覽次數:5134
日期:2018-12 瀏覽次數:6207
日期:2018-11 瀏覽次數:4455
日期:2018-08 瀏覽次數:4587
日期:2018-11 瀏覽次數:12625
日期:2018-09 瀏覽次數:5572
日期:2018-12 瀏覽次數:4826
日期:2018-10 瀏覽次數:4181
日期:2018-11 瀏覽次數:4523
日期:2018-12 瀏覽次數:6058
日期:2018-06 瀏覽次數:4003
日期:2018-08 瀏覽次數:5431
日期:2018-10 瀏覽次數:4454
日期:2018-12 瀏覽次數:4518
日期:2018-07 瀏覽次數:4356
日期:2018-12 瀏覽次數:4496
日期:2018-06 瀏覽次數:4376
日期:2018-11 瀏覽次數:4370
日期:2018-12 瀏覽次數:4244
日期:2018-12 瀏覽次數:5276
Copyright ? 2013-2018 Tadeng NetWork Technology Co., LTD. All Rights Reserved.