internal val innerLayoutNodeWrapper: LayoutNodeWrapper = InnerPlaceable(this)
innerLayoutNodeWrapper 是 InnerPlaceable 类型的对象 ,从图中可以看出其作用是执行 LayoutNode MeasurePolicy 中的 measure() 方法。
通过 15.1 我们知道 MeasureScope.measure 方法,测量子元素与容器本身的大小并决定如何在容器中布局子元素。子元素测量时又会从 LayoutNode 开始 ,再次执行蓝色部分的流程。
private val outerMeasurablePlaceable = OuterMeasurablePlaceable(this, innerLayoutNodeWrapper)
通过 15.2 我们知道 outerMeasurablePlaceable.wrapped 是以 innerLayoutNodeWrapper 为初始值遍历 modifier 将每个 Modifier 对象转换成 LayoutNodeWrapper 对象包装起来得到的。
至此我们流程图中我们还剩尺寸相关的 Modifier 是如何转换成约束传递下去的这一个问题没有解。
尺寸相关的 Modifier 是如何转换成约束
在 setModifier() 方法中所有嵌套的 LayoutNodeWrapper 都继承自 DelegatingLayoutNodeWrapper,与尺寸无关的 Modifier 对应的 LayoutNodeWrapper 没有重写 measure() 方法 ,会执行DelegatingLayoutNodeWrapper#measure 方法。例如: ModifiedDrawNode。
internal open class DelegatingLayoutNodeWrapper<T : Modifier.Element>(
override var wrapped: LayoutNodeWrapper,
open var modifier: T
) : LayoutNodeWrapper(wrapped.layoutNode) {
override fun measure(constraints: Constraints): Placeable = performingMeasure(constraints) {
//调用包装时 wrapped 的 measure 方法
val placeable = wrapped.measure(constraints)
measureResult = object : MeasureResult {
override val width: Int = wrapped.measureResult.width
override val height: Int = wrapped.measureResult.height
override val alignmentLines: Map<AlignmentLine, Int> = emptyMap()
override fun placeChildren() {
with(PlacementScope) {
placeable.place(-apparentToRealOffset)
}
}
}
return this
}
}
DelegatingLayoutNodeWrapper#measure 中会一层层向包装内部传递一直传递到 InnerPlaceable,这中间如果遇到 ModifiedLayoutNode(尺寸相关的 Modifier 都会解析成 ModifiedLayoutNode)
internal class ModifiedLayoutNode(
wrapped: LayoutNodeWrapper,
modifier: LayoutModifier
) : DelegatingLayoutNodeWrapper<LayoutModifier>(wrapped, modifier) {
override fun measure(constraints: Constraints): Placeable = performingMeasure(constraints) {
with(modifier) {
measureResult = measureScope.measure(wrapped, constraints)
this@ModifiedLayoutNode
}
}
}
进而执行 Modifier#measure 方法,假设此时的 Modifier 是 SizeModifier
override fun MeasureScope.measure(
measurable: Measurable,
constraints: Constraints
): MeasureResult {
//计算最大/最小尺寸约束
val wrappedConstraints = targetConstraints.let { targetConstraints ->
if (enforceIncoming) {
constraints.constrain(targetConstraints)
} else {
val resolvedMinWidth = if (minWidth != Dp.Unspecified) {
targetConstraints.minWidth
} else {
constraints.minWidth.coerceAtMost(targetConstraints.maxWidth)
}
val resolvedMaxWidth = if (maxWidth != Dp.Unspecified) {
targetConstraints.maxWidth
} else {
constraints.maxWidth.coerceAtLeast(targetConstraints.minWidth)
}
val resolvedMinHeight = if (minHeight != Dp.Unspecified) {
targetConstraints.minHeight
} else {
constraints.minHeight.coerceAtMost(targetConstraints.maxHeight)
}
val resolvedMaxHeight = if (maxHeight != Dp.Unspecified) {
targetConstraints.maxHeight
} else {
constraints.maxHeight.coerceAtLeast(targetConstraints.minHeight)
}
Constraints(
resolvedMinWidth,
resolvedMaxWidth,
resolvedMinHeight,
resolvedMaxHeight
)
}
}
// measurable 是传过来的 wrapped
// 将约束传递到下一层 wrapped 的 measure 中
val placeable = measurable.measure(wrappedConstraints)
return layout(placeable.width, placeable.height) {
placeable.placeRelative(0, 0)
}
}
SizeModifier 中设置的尺寸就这样转换成约束传递到下一层 wrapped 的测量中。
只有 MeasureAndLayoutDelegate#relayoutNodes 中的 LayoutNode 才会被测量
fun measureAndLayout(): Boolean {
require(root.isAttached)
require(root.isPlaced)
require(!duringMeasureLayout)
// we don't need to measure any children unless we have the correct root constraints
val rootConstraints = rootConstraints ?: return false
var rootNodeResized = false
if (relayoutNodes.isNotEmpty()) {
duringMeasureLayout = true
try {
relayoutNodes.popEach { layoutNode ->
根节点 root 在 AndroidComposeView#onMeasure 时先调用 measureAndLayoutDelegate.updateRootConstraints 将 root 添加到 relayoutNodes 中再开启的测量流程
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
trace("AndroidOwner:onMeasure") {
if (!isAttachedToWindow) {
invalidateLayoutNodeMeasurement(root)
}
val (minWidth, maxWidth) = convertMeasureSpec(widthMeasureSpec)
val (minHeight, maxHeight) = convertMeasureSpec(heightMeasureSpec)
val constraints = Constraints(minWidth, maxWidth, minHeight, maxHeight)
if (onMeasureConstraints == null) {
// first onMeasure after last onLayout
onMeasureConstraints = constraints
wasMeasuredWithMultipleConstraints = false
} else if (onMeasureConstraints != constraints) {
// we were remeasured twice with different constraints after last onLayout
wasMeasuredWithMultipleConstraints = true
}
measureAndLayoutDelegate.updateRootConstraints(constraints)
measureAndLayoutDelegate.measureAndLayout()
fun updateRootConstraints(constraints: Constraints) {
if (rootConstraints != constraints) {
require(!duringMeasureLayout)
rootConstraints = constraints
root.layoutState = NeedsRemeasure
relayoutNodes.add(root)
}
}
此外 LayoutNode#requestRemeasure 也会将其添加到 relayoutNodes 中。