Google 出品,Dart語言,Flutter Engine引擎,響應式設計模式,原生渲染。react
Flutter 是谷歌2018年發佈的跨平臺移動UI框架。與 react native 經過 Javascript 開發不一樣,Flutter 的編程語言是Dart,因此執行時並不須要 Javascript 引擎,但實際效果最終也經過原生渲染。web
其餘框架只是作了OEM封裝,Flutter能夠直接操做Skia進行繪製。 算法
從該架構圖可知,Flutter框架可分爲Framework層和Engine層;編程
框架(Framework)部分是用Dart語言寫的,也是本系列文章主要涉及的部分。canvas
引擎(Engine)部分是用C++實現的。引擎爲框架提供支撐,也是鏈接框架和系統(Android/iOS)的橋樑。設計模式
Flutter Framework: 整個框架層都是用Dart語言實現,該層提供一套基礎庫, 用於處理動畫、繪圖和手勢等。而且基於繪圖封裝了一套 UI組件庫,而且細分爲兩種風格的組件 。瀏覽器
Foundation、Animation、Painting、Gestures 爲 Dart 實現的 UI 層,提供動畫、手勢及繪製。markdown
Rendering 渲染層,依賴 UI 層,在運行時 Rendering 層會構建一個 Widget 樹,當有變化時,會根據必定的算法計算出有變化的部分,而後更新 Widget 樹。數據結構
Widgets 層是 Flutter 提供的的一套基礎組件庫,在基礎組件庫之上,Flutter 還提供了 Material 和 Cupertino 兩種視覺風格的組件庫。架構
Materail : Android風格的Widget
Cupertino: IOS風格的Widget
Flutter Engine
Skia 是一個開源的二維圖形庫,提供各類經常使用的 API,並可在多種軟硬件平臺上運行。谷歌 Chrome 瀏覽器、Chrome OS、安卓、火狐瀏覽器、火狐操做系統以及其它許多產品都使用它做爲圖形引擎。
Skia 由谷歌出資管理,任何人均可基於 BSD 免費軟件許可證使用 Skia。Skia 開發團隊致力於開發其核心部分, 並普遍採納各方對於 Skia 的開源貢獻。
由於沒有使用原生的 UI 和繪製框架,因此才保證了 Flutter 的高性能體驗。
Flutter Engine: 這是一個純 C++實現的 SDK,其中囊括了 Skia引擎、Dart運行時、文字排版引擎等。不過說白了,它就是 Dart的一個運行時,它能夠以 JIT、JIT Snapshot 或者 AOT的模式運行 Dart代碼。在代碼調用 dart:ui庫時,提供 dart:ui庫中 Native Binding 實現。 不過別忘了,這個運行時還控制着 VSync信號的傳遞、GPU數據的填充等,而且還負責把客戶端的事件傳遞到運行時中的代碼。
…/sdk/flutter/packages/flutter/lib
Dart可以使用Dart2Js編譯器把Dart代碼編譯成Js代碼。大多數原生App元素可以經過DOM實現,DOM實現不了的元素能夠經過Canvas來實現。
得益於 Engine 層,Flutter 甚至不使用移動平臺的原生控件, 而是使用本身 Engine 來繪製 Widget (Flutter的顯示單元),而 Dart 代碼都是經過 AOT 編譯爲平臺的原生代碼,因此 Flutter 能夠 直接與平臺通訊,不須要JS引擎的橋接。同時 Flutter 惟一要求系統提供的是 canvas,以實現UI的繪製。
對於Android平臺,Flutter引擎的C/C++代碼是由NDK編譯,在iOS平臺,則是由LLVM編譯,兩個平臺的Dart代碼都是AOT編譯爲本地代碼,Flutter應用程序使用本機指令集運行。Flutter正是是經過使用相同的渲染器、框架和一組widget,來同時構建iOS和Android應用,而無需維護兩套獨立的代碼庫。
經過platform channels 和本地進行通訊。
經過MethodChannel,Native也能調用Flutter的方法,這是一個雙向的通道。
Android顯示器運行在60幀/秒左右,一幀大概16.6ms。
繪製間隔時間大於16ms會出現卡頓現象。
在Flutter框架中存在着一個渲染流水線(Rendering pipline)。這個渲染流水線是由垂直同步信號(Vsync)驅動的,而Vsync信號是由系統提供的,若是你的Flutter app是運行在Android上的話,那Vsync信號就是咱們熟悉的Android的那個Vsync信號。
當Vsync信號到來之後,Flutter 框架會按照圖裏的順序執行一系列動做: 動畫(Animate)、構建(Build)、佈局(Layout)和繪製(Paint),最終生成一個場景(Scene)以後送往底層,由GPU繪製到屏幕上。
動畫(Animate)階段:由於動畫會隨每一個Vsync信號的到來而改變狀態(State),因此動畫階段是流水線的第一個階段。
構建(Build)在這個階段Flutter,在這個階段那些須要被從新構建的Widget會在此時被從新構建。也就是咱們熟悉的StatelessWidget.build()或者State.build()被調用的時候。
佈局(Layout)階段,這時會肯定各個顯示元素的位置,尺寸。此時是RenderObject.performLayout()被調用的時候。
繪製(Paint)階段,此時是RenderObject.paint()被調用的時候。
以上是整個渲染流水線的一個大體的工做過程。
Flutter app只有在狀態發生變化的時候須要觸發渲染流水線。當你的app什麼都不作的時候是不須要從新渲染頁面的。因此,Vsync信號須要Flutter app去調度。好比咱們都知道若是你的某個頁面須要發生變化的時候有可能會調用State.setState(),這個調用Flutter框架最終會發起一個調度Vsync信號的請求給底層。而後底層會在Vsync信號到來的時候驅動渲染流水線開始運做,最後把新的頁面顯示到屏幕上。
![]() |
Flutter框架渲染機制的一個示意圖。
整個渲染流水線是運行在UI線程裏的,以Vsync信號爲驅動,在框架渲染完成以後會輸出layer tree。
layer tree被送入engine,engine會把layer tree調度到GPU線程,在GPU線程內合成(compsite)layer tree,而後由Skia 2D渲染引擎渲染後送入GPU顯示。
這裏提到layer tree是由於咱們即將要分析的渲染流水線繪製階段最終輸出就是這樣的layer tree。
因此繪製階段並非簡單的調用paint()函數這麼簡單了,而是不少地方都涉及到layer tree的管理。
Flutter只關心向 GPU提供視圖數據,GPU的 VSync信號同步到 UI線程,UI線程使用 Dart來構建抽象的視圖結構,這份數據結構在 GPU線程進行圖層合成,視圖數據提供給 Skia引擎渲染爲 GPU數據,這些數據經過 OpenGL或者 Vulkan提供給 GPU。
![]() |
在Flutter中,大多數東西都是widget,而Widget是不可變的,僅支持一幀,而且在每一幀上不會直接更新,要更新而必須使用Widget的狀態。無狀態和有狀態 widget 的核心特性是相同的,每一幀它們都會從新構建,有一個State對象,它能夠跨幀存儲狀態數據並恢復它。 Flutter 上 Android 自帶了 Skia,Skia是一個 2D的繪圖引擎庫,跨平臺,因此能夠被嵌入到 Flutter的 iOS SDK中,也使得 Flutter Android SDK要比 iOS SDK小不少。
一個 StatelessWidget 是不能被改變的,好比:Icon、Text等。
若是你的控件一旦顯示,就不須要再作任何的變動,那麼你應該使用 StatelessWidget。
一個 StatefulWidget 是有狀態的,可變的。
它能夠改變本身的外觀,以響應用戶的操做或者數據的變化。
好比:CheckBox、Switch..
![]() |