ComposeUI规定:只允许一次测量,不允许重复测量。即每个父布局只对每个子组件测量一次,即测量复杂度变成了:O(n)。
ComposeUI引入了:**固有特性测量(Intrinsic Measurement)。**即 Compose 允许父组件在对子组件测量前先测量子组件的“固有尺寸”,这相当于上面说的两次测量的 第一次 “粗略测量“。
而这种固定特性测量是对整个组件布局树进行一次测量即可,从而避免了随着层级的加深而增加测量次数。
此处主要分析:固定特性测量的测量过程。此处先介绍LayoutNodeWrapper链构建
4.1 LayoutNodeWrapper
先来看两个核心结论:
-
子View都是以LayoutNode的形式,存在于Parent - children中的
-
给Layout的设置的modifier会以LayoutNodeWrapper链的形式存储在LayoutNode中,然后后续做相应变换
下面说明LayoutNodeWrapper的构建:
-
默认的LayoutNodeWrapper链即由LayoutNode , OuterMeasurablePlaceable, InnerPlaceable 组成
-
当添加了modifier时,LayoutNodeWrapper链会更新,modifier会作为一个结点插入到其中
internal val innerLayoutNodeWrapper: LayoutNodeWrapper = InnerPlaceable(this)private val outerMeasurablePlaceable = OuterMeasurablePlaceable(this, innerLayoutNodeWrapper)override fun measure(constraints: Constraints) = outerMeasurablePlaceable.measure(constraints)override var modifier: Modifier = Modifier set(value) { // …… code field = value // …… code // 创建新的 LayoutNodeWrappers 链 // foldOut 相当于遍历 modifier val outerWrapper = modifier.foldOut(innerLayoutNodeWrapper) { mod /📍 modifier/ , toWrap -> var wrapper = toWrap if (mod is OnGloballyPositionedModifier) { onPositionedCallbacks += mod } if (mod is RemeasurementModifier) { mod.onRemeasurementAvailable(this) } val delegate = reuseLayoutNodeWrapper(mod, toWrap) if (delegate != null) { wrapper = delegate } else { // …… 省略了一些 Modifier判断 if (mod is KeyInputModifier) { wrapper = ModifiedKeyInputNode(wrapper, mod).assignChained(toWrap) } if (mod is PointerInputModifier) { wrapper = PointerInputDelegatingWrapper(wrapper, mod).assignChained(toWrap) } if (mod is NestedScrollModifier) { wrapper = NestedScrollDelegatingWrapper(wrapper, mod).assignChained(toWrap) } // 布局相关的 Modifier if (mod is LayoutModifier) { wrapper = ModifiedLayoutNode(wrapper, mod).assignChained(toWrap) } if (mod is ParentDataModifier) { wrapper = ModifiedParentDataNode(wrapper, mod).assignChained(toWrap) } } wrapper } outerWrapper.wrappedBy = parent?.innerLayoutNodeWrapper outerMeasurablePlaceable.outerWrapper = outerWrapper …… }// 假设:给Layout设置一些modifierModifier.size(100.dp).padding(10.dp).background(Color.Blue)
对应的LayoutNodeWrapper链如下图所示
image.png
这样一直链式调用下一个的measure,直到最后一个结点InnerPlaceable,最终调用到了自定义Layout时写的measure()
4.2 固有特性测量-实现原理
结论:LayoutNodeWrapper链中插入了一个Modifier
@Stablefun Modifier.height(intrinsicSize: IntrinsicSize) = when (intrinsicSize) { IntrinsicSize.Min -> this.then(MinIntrinsicHeightModifier) IntrinsicSize.Max -> this.then(MaxIntrinsicHeightModifier)}private object MinIntrinsicHeightModifier : IntrinsicSizeModifier { override fun MeasureScope.measure( measurable: Measurable, constraints: Constraints ): MeasureResult { //正式测量前先根据固有特性测量获得一个约束 val contentConstraints = calculateContentConstraints(measurable, constraints) //正式测量 val placeable = measurable.measure( if (enforceIncoming) constraints.constrain(contentConstraints) else contentConstraints ) return layout(placeable.width, placeable.height) { placeable.placeRelative(IntOffset.Zero) } } override fun MeasureScope.calculateContentConstraints( measurable: Measurable, constraints: Constraints ): Constraints { val height = measurable.minIntrinsicHeight(constraints.maxWidth) return Constraints.fixedHeight(height) } override fun IntrinsicMeasureScope.maxIntrinsicHeight( measurable: IntrinsicMeasurable, width: Int ) = measurable.minIntrinsicHeight(width)}
汇总说明:
-
IntrinsicSize.Min其实也是个Modifier
-
MinIntrinsicHeightModifier会在测量之间,先调用calculateContentConstraints计算约束
-
calculateContentConstraints中则会递归地调用子项的minIntrinsicHeight,并找出最大值,这样父项的高度就确定了
-
固有特性测量完成后,再调用measurable.measure,开始真正的递归测量
至此,关于Compose UI解决布局嵌套层级问题及其原理讲解完毕。
===========================================================
给大家分享我收集的Android源码解析学习资料,希望对你有用,期待与大家一同进步
1.深入解析微信 MMKV 源码
2.深入解析阿里巴巴路由框架 ARouter
源码
3.深入解析 AsyncTask 源码(一款
Android 内置的异步任务执行库)
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)
最后
针对Android程序员,我这边给大家整理了一些资料,包括不限于高级UI、性能优化、架构师课程、NDK、混合式开发(ReactNative+Weex)微信小程序、Flutter等全方面的Android进阶实践技术;希望能帮助到大家,也节省大家在网上搜索资料的时间来学习,也可以分享动态给身边好友一起学习!
-
Android前沿技术大纲
-
全套体系化高级架构视频
Android高级架构资料、源码、笔记、视频。高级UI、性能优化、架构师课程、混合式开发(ReactNative+Weex)全方面的Android进阶实践技术,群内还有技术大牛一起讨论交流解决问题。
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
高级UI、性能优化、架构师课程、混合式开发(ReactNative+Weex)全方面的Android进阶实践技术,群内还有技术大牛一起讨论交流解决问题。**
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!