前言
StatelessWidget 和 StatefulWidget 只是用來(lái)組裝控件的容器算撮,并不負(fù)責(zé)組件最后的布局和繪制疚脐。在 Flutter 中亿柑,布局和繪制工作實(shí)際上是在 Widget 的另一個(gè)子類 RenderObjectWidget 內(nèi)完成的。
RenderObjectWidget為RenderObjectElement提供配置信息棍弄。
RenderObjectElement包裝了RenderObject望薄,RenderObject為應(yīng)用程序提供真正的渲染。
源碼
abstract class RenderObjectWidget extends Widget {
const RenderObjectWidget({ Key? key }) : super(key: key);
@override
@factory
RenderObjectElement createElement();
@protected
@factory
RenderObject createRenderObject(BuildContext context);
@protected
void updateRenderObject(BuildContext context, covariant RenderObject renderObject) { }
@protected
void didUnmountRenderObject(covariant RenderObject renderObject) { }
}
- createElement 需要返回一個(gè)繼承RenderObjectElement的類
- createRenderObject 創(chuàng)建 Render Widget 對(duì)應(yīng)的 Render Object呼畸,同樣子類需要重寫(xiě)該方法痕支。該方法在對(duì)應(yīng)的 Element 被掛載到樹(shù)上時(shí)調(diào)用(Element.mount),即在 Element 掛載過(guò)程中同步構(gòu)建了「Render Tree」
- updateRenderObject 在 Widget 更新后蛮原,修改對(duì)應(yīng)的 Render Object卧须。該方法在首次 build 以及需要更新 Widget 時(shí)都會(huì)調(diào)用;
- didUnmountRenderObject 「Render Object」從「Render Tree」上移除時(shí)調(diào)用該方法。
RenderObjectElement 源碼
abstract class RenderObjectElement extends Element {
RenderObject _renderObject;
@override
void mount(Element parent, dynamic newSlot) {
super.mount(parent, newSlot);
_renderObject = widget.createRenderObject(this);
attachRenderObject(newSlot);
_dirty = false;
}
@override
void update(covariant RenderObjectWidget newWidget) {
super.update(newWidget);
widget.updateRenderObject(this, renderObject);
_dirty = false;
}
...
}
- mount: RenderObject 對(duì)象的創(chuàng)建花嘶,以及與渲染樹(shù)的插入工作笋籽,插入到渲染樹(shù)后的 Element 就可以顯示到屏幕中了。
- update: 如果 Widget 的配置數(shù)據(jù)發(fā)生了改變察绷,那么持有該 Widget 的 Element 節(jié)點(diǎn)也會(huì)被標(biāo)記為 dirty干签。在下一個(gè)周期的繪制時(shí),F(xiàn)lutter 就會(huì)觸發(fā) Element 樹(shù)的更新拆撼,并使用最新的 Widget 數(shù)據(jù)更新自身以及關(guān)聯(lián)的 RenderObject 對(duì)象容劳,接下來(lái)便會(huì)進(jìn)入 Layout 和 Paint 的流程。而真正的繪制和布局過(guò)程闸度,則完全交由 RenderObject 完成竭贩。
RenderObject 主要處理一些固定的操作,如:布局莺禁、繪制和 Hit testing留量。 與ComponentElement一樣RenderObjectElement也是抽象類,不同的是ComponentElement不會(huì)直接創(chuàng)建RenderObject,而是間接通過(guò)創(chuàng)建其他Element創(chuàng)建RenderObject哟冬。
RenderObjectElement主要有三個(gè)系統(tǒng)的子類楼熄,分別處理renderObject作為child時(shí)的不同情況。
- LeafRenderObjectElement:葉子渲染對(duì)象對(duì)應(yīng)的元素浩峡,處理沒(méi)有children的renderObject可岂。
- SingleChildRenderObjectElement:處理只有單個(gè)child的renderObject。
- MultiChildRenderObjectElement: 處理有多個(gè)children的渲染對(duì)象
有時(shí)RenderObject的child模型更復(fù)雜一些翰灾,比如多維數(shù)組的形式缕粹,則可能需要基于RenderObjectElement實(shí)現(xiàn)一個(gè)新的子類。
RenderObjectElement 充當(dāng)widget與renderObject之間的中介者纸淮。需要進(jìn)行方法覆蓋平斩,以便它們返回元素期望的特定類型,例如:
class FooElement extends RenderObjectElement {
@override
Foo get widget => super.widget;
@override
RenderFoo get renderObject => super.renderObject;
}
widget返回Foo咽块,renderObject 返回RenderFoo
系統(tǒng)常用組件與RenderObjectElement:
常用組件 | Widget(父級(jí)) | Element |
---|---|---|
Flex/Wrap/Flow/Stack | MultiChildRenderObjectWidget | MultiChildRenderObjectElement |
RawImage(Imaget)/ErrorWidget | LeafRenderObjectWidget | LeafRenderObjectElement |
Offstage/SizedBox/Align/Padding | SingleChildRenderObjectWidget | SingleChildRenderObjectElement |
RenderObject源碼
abstract class RenderObject extends AbstractNode with DiagnosticableTreeMixin implements HitTestTarget {
...
void layout(Constraints constraints, { bool parentUsesSize = false }) {...}
void paint(PaintingContext context, Offset offset) { }
}
布局和繪制完成后绘面,接下來(lái)的事情就交給 Skia 了。在 VSync 信號(hào)同步時(shí)直接從渲染樹(shù)合成 Bitmap侈沪,然后提交給 GPU揭璃。