作为系列文章的第七篇,本篇主要在前文的基础上,再深入了解 Widget 和布局中的一些常识性问题。
文章汇总地址:
在第六篇中我们知道了 Widget
、Element
、RenderObject
三者之间的关系,其中我们最为熟知的 Widget
,作为“配置文件”的存在,在 Flutter 中它的功能都是比较单一的,属于 “颗粒度比较细的存在” ,写代码时就像拼乐高“积木”,那这“积木”究竟怎么拼的?下面就 深入 去挖挖有意思的东西吧。( ̄▽ ̄)
一、单子元素布局
在 Flutter 单个子元素的布局 Widget 中,Container
无疑是被用的最广泛的,因为它在“功能”上并不会如 Padding
等 Widget 那样功能单一,这是为什么呢?
究其原因,从下图源码可以看出,Container
其实也只是把其他“单一”的 Widget 做了二次封装,然后通过配置来达到“多功能的效果”而已。
接着我们先看 ConstrainedBox
源码,从下图源码可以看出,它是继承了 SingleChildRenderObjectWidget
,关键是 override 了 createRenderObject
方法,返回了 RenderConstrainedBox
。
这里体现了第六篇中的 Widget 与 RenderObject 的关系
是的,RenderConstrainedBox
就是继承自 RenderBox
,从而实现RenderObject
的布局,这里我们得到了它们的关系如下 :
Widget | RenderObject |
---|---|
ConstrainedBox | RenderConstrainedBox |
然后我们继续对其他每个 Widget 进行观察,可以看到它们也都是继承SingleChildRenderObjectWidget
,而“简单来说”它们不同的地方就是 RenderObject
的实现了:
Widget | RenderBox (RenderObject) |
---|---|
Align | RenderPositionedBox |
Padding | RenderPadding |
Transform | RenderTransform |
Offstage | RenderOffstage |
所以我们可以总结:真正的布局和大小计算等行为,都是在 RenderBox
上去实现的。 不同的 Widget 通过各自的 RenderBox
实现了“差异化”的布局效果。所以找每个 Widget 的实现,找它的 RenderBox
实现就可以了。(当然,另外还有 RenderSliver
,这里暂时不讨论)
这里我们通过 Offstage
这个Widget 小结下,Offstage
这个 Widget 是通过 offstage
标志控制 child 是否显示的效果,同样的它也有一个 RenderOffstage
,如下图,通过 RenderOffstage
的源码我们可以“真实”看到 offstage
标志位的作用:
所以大部分时候,我们的 Widget 都是通过实现 RenderBox
实现布局的 ,那我们可不可抛起 Widget 直接用 RenderBox
呢?答案明显是可以的,如果你闲的🥚疼的话!
Flutter 官方为了治疗我们“🥚疼”,提供了一个叫 CustomSingleChildLayout
的类,它抽象了一个叫 SingleChildLayoutDelegate
的对象,让你可以更方便的操作 RenderBox
来达到自定义的效果。
如下图三张源码所示,SingleChildLayoutDelegate
的对象提供以下接口,并且接口 前三个 是按照顺序被调用的,通过实现这个接口,你就可以轻松的控制RenderBox 的 布局位置、大小 等。
二、多子元素布局
事实上“多子元素布局”和单子元素类似,通过“举一反三”我们就可以知道它们的关系了,比如:
Row
、Colum
都继承了Flex
,而 Flex 继承了MultiChildRenderObjectWidget
并通过RenderFlex
创建了RenderBox
;Stack
同样继承MultiChildRenderObjectWidget
并通过RenderStack
创建了RenderBox
;
Widget | RenderBox (RenderObject) |
---|---|
Row/Colum/Flex | RenderFlex |
Stack | RenderStack |
Flow | RenderFlow |
Wrap | RenderWrap |
同样“多子元素布局”也提供了 CustomMultiChildLayout
和 MultiChildLayoutDelegate
满足你的“🥚疼”需求。
三、多子元素滑动布局
滑动布局作为 “多子元素布局” 的另一个分支,如 ListView
、GridView
、Pageview
,它们在实现上要复杂的多,从下图一个的流程上我们大致可以知道它们的关系:
由上图我们可以知道,流程最终回产生两个 RenderObject :
-
RenderSliver
:Base class for the render objects that implement scroll effects in viewports. -
RenderViewport
:A render object that is bigger on the inside.
/// [RenderViewport] cannot contain [RenderBox] children directly. Instead, use
/// a [RenderSliverList], [RenderSliverFixedExtentList], [RenderSliverGrid], or
/// a [RenderSliverToBoxAdapter], for example.
并且从 RenderViewport
的说明我们知道,RenderViewport
内部是不能直接放置 RenderBox
,需要通过 RenderSliver
大家族来完成布局。而从源码可知:RenderViewport
对应的 Widget Viewport
就是一个 MultiChildRenderObjectWidget
。 (你看,又回到 MultiChildRenderObjectWidget
了吧。)
再稍微说下上图的流程:
-
ListView
、Pageview
、GridView
等都是通过Scrollable
、ViewPort
、Sliver
大家族实现的效果。这里简单不规范描述就是:一个“可滑动”的控件,嵌套了一个“视觉窗口”,然后内部通过“碎片”展示 children 。 -
不同的是
PageView
没有继承SrollView
,而是直接通过NotificationListener
和ScrollNotification
嵌套实现。
注意
TabBarView
内部就是:NotificationListener
+PageView
是不是觉得少了什么?哈哈哈,有的有的,官方同样提供了解决“🥚疼”的自定义滑动 CustomScrollView
,它继承了 ScrollView
,可通过 slivers 参数实现布局,这些 slivers
最终回通过 Scrollable
的 buildViewport
添加到 ViewPort
中,如下代码所示:
CustomScrollView(
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)
最后
这里我特地整理了一份《Android开发核心知识点笔记》,里面就包含了自定义View相关的内容
除了这份笔记,还给大家分享 Android学习PDF+架构视频+面试文档+源码笔记,高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料这几块的内容。非常适合近期有面试和想在技术道路上继续精进的朋友。
分享上面这些资源,希望可以帮助到大家提升进阶,如果你觉得还算有用的话,不妨把它们推荐给你的朋友~
喜欢本文的话,给我点个小赞、评论区留言或者转发支持一下呗~
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门即可获取!
话,不妨把它们推荐给你的朋友~**
喜欢本文的话,给我点个小赞、评论区留言或者转发支持一下呗~