Flutter能夠做到跨平臺(tái)是因?yàn)槭褂玫氖荢kia渲染引擎來繪制UI,不僅可以保證Android和iOS上UI的一致性,而且也可以避免對(duì)原生控件依賴而帶來的限制及高昂成本。
我們下面通過Flutter的框架和Flutter中的三棵樹來詳細(xì)了解一下Flutter的渲染原理
Flutter框架

Flutter Engine層:
這是一個(gè)純C++實(shí)現(xiàn)的SDK,其中包括了Skia引擎、Dart運(yùn)行時(shí)、文字排版引擎等。在代碼調(diào)用dart:ui庫(kù)時(shí),調(diào)用最終會(huì)走到Engine層,然后實(shí)現(xiàn)真正的繪制邏輯。
Flutter Framework層:
Framework層可大致分為三層:
1,最下面兩層:(Foundation和Animation、Painting、Gestures)是dart的UI層,對(duì)應(yīng)的是Flutter中的dart:ui包,它是Flutter引擎暴露的底層UI庫(kù),提供動(dòng)畫、手勢(shì)、及繪制能力。
2,Rendering層,這一層是一個(gè)抽象的布局層,它依賴于dart UI層,Rendering層會(huì)構(gòu)建一個(gè)UI樹,當(dāng)UI樹有變化時(shí),會(huì)計(jì)算出有變化的部分,然后更新UI樹,最終將UI樹繪制到屏幕上,這個(gè)過程類似于React中的虛擬DOM。Rendering層可以說是Flutter UI框架最核心部分,它除了確定每個(gè)UI元素的位置、大小之外還要進(jìn)行坐標(biāo)變換、繪制(調(diào)用底層dart:ui)。
3,Widgets層是Flutter提供的一套基礎(chǔ)組件庫(kù),在基礎(chǔ)庫(kù)之上,F(xiàn)lutter還提供了Material和Cupertino兩種風(fēng)格的組件庫(kù)。而我們?cè)贔lutter開發(fā)中,打交道最多的也是這兩層。
Flutter中的三棵樹:
在Flutter中幾乎所有的對(duì)象都是Widget。Widget不僅可以表示UI元素,也可以表示一些功能性的組件,比如手勢(shì)、主題等。Widget的功能是“描述一個(gè)UI元素的配置數(shù)據(jù)”,Widget其實(shí)并不是表示最終繪制在設(shè)備屏幕上的顯示元素,而它只是描述顯示元素的一個(gè)配置數(shù)據(jù)。
最終的UI樹其實(shí)是由一個(gè)個(gè)獨(dú)立的Element節(jié)點(diǎn)構(gòu)成。
從創(chuàng)建到渲染的大體流程是:根據(jù)Widget生成Element,然后創(chuàng)建響應(yīng)的RedderObject并關(guān)聯(lián)到Element.renderObject屬性上,最后再通過RenderObject來完成布局排列和繪制。
我們可以認(rèn)為Flutter的UI系統(tǒng)包含三棵樹:Widget樹、Element樹、渲染樹。他們的依賴關(guān)系是:Element樹根據(jù)Widget樹生成,而渲染樹又依賴于Element樹。

Widget:
Widget里面存儲(chǔ)了一個(gè)視圖的配置信息,包括布局、屬性等。它是一份輕量的數(shù)據(jù)結(jié)構(gòu),在構(gòu)建時(shí)是結(jié)構(gòu)樹,它不參與直接繪制,所以說Widget僅僅是配置文件,F(xiàn)lutter團(tuán)隊(duì)對(duì)它做了優(yōu)化,頻繁的創(chuàng)建/銷毀它們,都不會(huì)存在明顯的性能問題。
Widget包含StatelessWidget和StatefulWidget兩個(gè)常用類,StatelessWidget是無狀態(tài)變化的類,需要重新展示時(shí)得重新new,StatefulWidget是有狀態(tài)變化的類,state存放于中間,通過調(diào)用state.setState()才會(huì)觸發(fā)該節(jié)點(diǎn)及以下整個(gè)子樹更新。
Element:
Element是Widget的抽象,當(dāng)一個(gè)Widget首次被創(chuàng)建的時(shí)候,那么這個(gè)Widget會(huì)通過Widget.createElement,創(chuàng)建一個(gè)element,掛載到Element Tree遍歷視圖樹。在attachRootWidget函數(shù)中,把widget交給RenderObjectToWidgetAdapter這座橋梁,Element創(chuàng)建的同時(shí)還持有Widget和RenderObject的引用。構(gòu)建系統(tǒng)通過遍歷Element Tree來創(chuàng)建RenderObject,每一個(gè)Element都具有一個(gè)唯一的key,當(dāng)觸發(fā)視圖更新時(shí),只會(huì)更新標(biāo)記的需變化的Element。
RenderObject:
RenderObject作為UI視圖的描述方式,其中含有4個(gè)重用的屬性和方法。
constraints:從parent傳遞過來的約束。
parentData:這里面攜帶的是parent渲染child的時(shí)候所用到的數(shù)據(jù)。
performLayout():此方法用于布局所有的child。
paint():這個(gè)方法用于繪制自己或者child。
RenderObject Tree構(gòu)建為Canvas的所需描述數(shù)據(jù),加入到Layer Tree中,最終在Flutter Engine中進(jìn)行視圖合成并光柵化交給GPU。