Flutter中的三棵树是如何完成绘制的

定义 Widget:存放渲染内容、它只是一个配置数据结构,创建是非常轻量的,在页面刷新的过程中随时会重建。 其中Widget根据功能可以分为三类: 组合类StatelessWidget/StatefulWidget:比如我们常见的Container就是一个组合类的控件,它主要负责组合封装多个其他负责绘制的原子组件。 代理类inheritedwidget:它的父类是ProxyWidget,顾名思义。简单来说,InheritedWidget 的作用是向它的子 Widget 有效地传播和分享数据,当 InheritedWidget 作为一个Parent Widget时,它下面的Widget tree的所有Widget都可以去和 InheritedWidget 发生数据传递和交互。当数据发生改变时,一部分控件需要 rebuild,另外的控件不需要 rebuild 的时候,可以使用 InheritedWidget。 绘制类RenderObjectWidget:RenderObjectWidget会负责创建出负责实际渲染的RenderObject对象,RenderObject负责实际的layout()和paint()。后期有空,我会手动写一个RenderObject。 Element: 是分离 WidgetTree 和真正的渲染对象的中间层,可以看成flutter的骨架。 Widget 用来描述对应的Element 属性,同时持有Widget和RenderObject,存放上下文信息,通过它来遍历视图树,支撑UI结构。 其中Element可以根据功能分成两大类: 组合类ComponentElement:主要包括如下 StatelessElement / StatefulElement / ProxyElement 子类;其中各Element都是与 Widget 对应的。 绘制类RenderObjectElement:RenderObjectElement对应的是RenderObjectWidget。 RenderObject用于应用界面的布局和绘制,负责真正的渲染,保存了元素的大小,布局等信息。 当应用启动时 Flutter 会遍历并创建所有的 Widget 形成 Widget树,通过调用 Widget 上的 createElement() 方法创建每个 Element 对象,形成 Element 树。最后调用 Element 的 createRenderObject() 方法创建每个渲染对象,形成一个 RenderObject 树。 Widget => Element 如何通过Widget更新Element: Element/ComponentElement: 单个Element时候通过updateChild方法更新; E } l e i } f i } } r m / f i f e e 如 i r n i } } } e n t n 果 ( f e a ( / f l e u t n n d t l c 新 i n e i c n e d n s o w r ? e e ( e u h 旧 ( f e l / f h e l / e e e l C n w w c a r E i w c u w s 可 u i w s 其 a w d h u W W h c n l l i h ( p C e 以 ( p l C e 他 c C { i n p i i i t e d d i c d h u c d d h 情 t h c l e d d d l i n m g l h a i i p h a . i { 况 i i h d w a g g d v u e ! e d i t l f d i t u l , v l i C t e e a l n = t . l e d a l e p d 移 a d l = h e t t ! t l t 相 w d S ( t d S d 除 t d i C 是 = e ; n 同 i . l = W e . l a = 旧 e = 是 i l h n = C n u 的 d s o i 的 s o t 的 C n n d i u = n h e l 情 g l t c d 情 l t e c , h i u f ; l l u i w l 况 e o F h g 况 o F ( h 重 i n l l d l n l l C ) t t o i e , t o n i 新 l f l a ( , u l d h r l t 也 r e l i d l , t E 并 l ) ( i { = ! C d . 就 ! C w d n ( a 这 e l 且 l c l = = h ; c 是 = h W ; f c t 里 W e o ) h d i a r i i l h e 直 i m l i ; n n l n u n l d a i W 接 d e d { l e e d U n e d g t l i i g n d w w ( p t w ( e e d d n e t c ) W S c d i S c t W ) g f t ? h ; i l h a m l h ) i ; e l ( i d o i t e o i ; d t a n c l g t l e t t l g ( t e h d e ) d ( y ) d e n e w i 非 t , c p , t e 新 W l n ) h e 新 w 的 i d u n i 和 n 的 W w d , l { e l k e w i i g l w d e w i d d e W , S . y S d g g t i 直 l w 相 l g e e , d 接 o i 同 o e t t g d t d t t , , n e e ) g ) , 会 e t a ; e ; 会 n 创 w ? c t 创 e 建 S t , 建 w e l n i e S l o e v n l l e t w a e e o m ) W t w m t e ; i e W e ) n d C i n ; t g h d t e i g t l e , d t ) O ) b j { e c t ? n e w S l o t ) { 大致归纳一下,如下表: ...

2021-09-29 · 22 min · 4639 words · CubeGao

如何在ListView中优雅的嵌套ListView

前言 日常的开发工作中,经常会遇到列表中嵌套ListView的需求。具体情况也分为两种。 1.竖向ListView嵌套横向ListView 常见的需求:竖向ListView行数不限制,横向ListView的列数不限制。具体情况如下图。 代码如下: L i s t V i e w ( c ] h , i T S ) l e t , d x a c ] r t c h , e ( k i I ) S P ) n ' ( l g , i o , : L d n c ) z s c ) i r o h , e i h , [ s e r i o c d t i s i t n e l p h B i l c t V : P d a i o o d r e i o : c l x n : o m e [ i i d ( e l B w n O t : w d L l u ' t p y i . i D i ) e a : I d f s i l , r c t t i t r d ( i 0 e h l V e e t . m : l i c r y 0 ( ( e t : ( , ) d w i , o . o u b n _ b u : , l i e l A i . d x n i e i d n r s e f ( . x i h ) n o i r = t i > y z ) o I , n t t e a m l ( , ) , Stack存在无Positioned包裹的子组件,决定Stack尺寸的是无位置的组件中的最大的尺寸,Positioned不会影响Stack的尺寸。(当然如果子类全部是Positioned包裹的子组件,Stack会将自身尺寸设置为父级布局约束所允许的最大尺寸,为对齐子组件创造条件。)。 此处用Positioned.fill,让ListView尽量占满整个Stack。 接下来设置宽度,利用SizedBox的向下传递约束,向上传递尺寸的特性。用SizedBox(width: double.infinity)把宽度撑开到整个屏幕的宽度。 接下来算出Item的高度,用Item的高度撑开Stack的高度。 此处用Item的初衷只是为了定制高度,不能让Item显示在屏幕上,所以用Opacity隐藏Item,为了忽略掉事件响应,最后用上IgnorePointer。 ...

2021-07-06 · 3 min · 531 words · CubeGao

如何解决Flutter中的依赖冲突

前言 今天更新第三方依赖库,执行flutter pub get后,报错了 Because project depends on path_provider 1.6.8 which doesn’t match any versions, version solving failed. pub get failed (1; Because project depends on path_provider 1.6.8 which doesn’t match any versions, version solving failed.) Process finished with exit code 1 分析为什么会出现冲突 查看文件pubspec.yaml是这个样子的 d e p p e a n t d h e _ n p c r i o e v s i : d e r : ^ 1 . 6 . 8 我们在开发Flutter项目中,经常会依赖第三方库。如果两个第三方库,同时依赖了某个库。比如库A要求path_provider最低版本为1.5.0,库B要求path_provider最低版本为1.6.8,当path_provider的版本更新为1.6.8时,虽然符合库B的要求,但是不符合库A的要求,这个时候就冲突报错了。 ...

2021-04-22 · 2 min · 276 words · CubeGao

Flutter中的BuildContext到底是什么

前言 首先我们看看官方的定义: [BuildContext] objects are actually [Element] objects. The [BuildContext] interface is used to discourage direct manipulation of [Element] objects. [BuildContext] 对象实际上是 [Element] 对象。 [BuildContext] 接口用于阻止直接操作 [Element] 对象。 根据官方这段注释,可以了解到BuildContext 实际上就是 Element 对象,产生的意义主要是为了防止开发者直接操作 Element 对象。 如何使用BuildContext 写一段大家很熟悉的代码 c } l a i } s n o s t i s } d e ) _ _ t _ ; M c _ S c y o i t o H u n a u o n c t n m t r e t e e e ( e P r m ( r a e ) + g = n + e t { ; S 0 C t ; o a u t n e t e e r x ( t ) e n { d s S t a t e < M y H o m e P a g e > { 这里有同学好奇,_counter++;不写在setState的回调方法里可以生效吗?答案是可以的。但是我更推荐把和状态更新相关的操作,放在回调里面。这样更加的工程化管理。因为一个项目经过长时期的更新,你可能无法分清,这个方法里面的setState,是不是实际上起作用了,会造成代码冗余。 ...

2021-03-11 · 7 min · 1413 words · CubeGao

Flutter 嵌套过深的解决方案

写代码容易,读代码难。功能是都实现了,但是对维护人员来说,简直就是灾难。 ##背景 Flutter 注重组合而非继承,要想搭建出 UI,需要组合不同功能的 Widget,如布局 Widget、响应 Widget、控件 Widget 等才能搭建出一个功能完善的UI界面,这便导致了嵌套地狱: 在顶级Widget的构造器中内嵌众多 Widget。 像下面这个例子,其实都不是最多层的,只要你卖力,可以超乎想象的))))))))))))))))))..... c } l a @ W } s o i s v d r ) e g e ; F r e t b ) r r t u o , o i r d c ] s d b n y h , t e u : i n n ) e i n l e e , d l e n d w w c ) G d w e r h , l ( w e C c c C i c ) a B S n o o h e l h , s u c S : n n i n d i f c ) s i a t s s l t : l i h , l f a < t t d e d l i o c ) e d f c W r r : r n : t l p h , x C o k i a a ( e e d a i w h d ) c ) t o l ( d i i n w n r : c l i e e , h , e n d g n n e e : i d d i c c i c n t ( e e t w C w O t : t g o o l h d e t d s l I p y h h r l d i s x > B : F i B m a : n : t a o : l t [ o l p a a c e : t r d s S x c u R c g i 0 w 2 i : n : t t c ( o t e k e t . 0 2 o e y a o n t c d F y 5 C 0 0 n C w n l t n s e t r i ( , o . 0 : o e e e t t r ( o l n 0 . l C w : l e L p t t , 0 n o e e x B o F e a , e r n T T s t o g i r i w s t e h s ) x o l . n . e x e W C ( t b e B g r t m i { o ) e l r o r ( ( e d n ) r u ( x e ' . g s , ( r D y F o e t ( e . r f t r s c s o ( a i o h s c { i g r a t o n m a d e n t a t e d t s X i 2 ' e . : o 0 , x e n 0 t x 1 ( , ) p 0 . a . t n 0 e d , x ( t ) s T , i h g e m m a e Y . : h e 1 a 0 d . l 0 i ) n , e 2 ) , 在IDE上面看到是这样的。 ...

2020-01-03 · 37 min · 7793 words · CubeGao

Flutter 从入门到放弃

##看看历史 你想想一套代码,移动端、web端、pc端都搞定!这生产力!非常值得学习了。 2015年5月 Dart 开发者峰会上,亮相了基于Dart 语言的移动应用程序开发框架Sky ,后更名为 Flutter。Dart语言2011年诞生,起初的竞对目标是Js,2016年谷歌的AdWords、AdSense和Fiber项目团队开始把Dart融入他们的前端应用开发。一项当时的内部报告表明,Dart可以帮助他们提升25%到100%的前端开发效率。谷歌内部的Dart代码量比去年增长了3.5倍。 5月7日 , Google i/O大会 官方宣布,Flutter 1.5 预览版来了,已支持移动、Web、桌面和嵌入式设备,也意味着它正式成为了支持多平台的轻量级 UI 框架,对于开发者而言越来越友好! ##看看架构 Flutter for Mobile Flutter for web ![C827C2BDF29EBA36E7DD6A10C26A4861.jpg][2] ##动手鼓捣 一个最简单的Flutter应用程序,只需一个widget即可! i } m o p i r ) o d u ; r n n ) t m A e , a p w c ) ' i p h , p n ( C i ' t a ( e l H e c ) n d e x k t : l t a { e l D g r n o i e ( e , r : w e f w c l T o t u e r i t x l o t t d n e ( ! : r ' / , T m e a x t t e D r i i r a e l c . t d i a o r n t . ' l ; t r , UIView 相当于 Flutter 中的什么? 在 iOS 中,构建 UI 的过程中将大量使用view对象。这些对象都是 UIView 的实例。它们可以用作容器来承载其他的 UIView,最终构成你的界面布局。 ...

2019-06-10 · 7 min · 1355 words · CubeGao