15.2 Compose 源码解析之测量、布局(二)—— Modifier

434 阅读3分钟

Modifier  我们第三章就介绍过,回头去看了一眼,呃...

F24D2B83-2C87-4E0E-A0A8-5AB204F1FFA6.png

如图 Modifier 共有三个直接实现子类

  • 伴生对象 Modifier ,方便使用  Modifier.xxx().xxx() 形式调用
  • Element 单个 Modifier ,它的直接实现子类都是接口,相当于按功能分类,实现具体功能的 Modifier 都在下一级
  • CombinedModifier  包装类,配合 Modifier.then 方法将 Modifier.xxx().xxx() 中的每个 Modifier 一层一层包装在一起

Modifier 包装与遍历

包装

Modifier 伴生对象的 then() 方法是返回参数中的 Modifer 对象

companion object : Modifier {
	override infix fun then(other: Modifier): Modifier = othe
}

Modifier then() 方法的默认实现是当参数不是 Modifier 伴生对象时,将参数与当前 Modifer 对象使用 CombinedModifier 组合在一起

@Stable
interface Modifier {
    infix fun then(other: Modifier): Modifier 
        if (other === Modifier) this else CombinedModifier(this, other)
}

CombinedModifier 的 outer 和 inner 属性配合 then() 方法对 Modifier 进行包装

class CombinedModifier(
    private val outer: Modifier
    private val inner: Modifier
) : Modifier {}

我们以下面的代码为例进行本问的分析。

modifier = Modifier.size(200.dp,100.dp).background(Color.LightGray).padding(8.dp)

size() 、background()、padding() 这些拓展方法实现都是使用 then() 方法与对应的 Modifier 对象包装后返回一个 CombinedModifier 对象

fun Modifier.size(width: Dp, height: Dp) = this.then( SizeModifier(/*...*/) )

我们在 Compose 函数中使用的 modifier 参数就这样一层一层的包装在了一起。

24F84FB7-6E06-44BE-B913-2A683439AE2A.png

遍历

modifier 既然是包装起来的对象,那么为什么这里成了遍历而不是拆装呢?

我们来看一下 Element  和 CombinedModifier 中 foldIn()的源码( foldOut()省略 )

interface Element : Modifier {
	override fun <R> foldIn(initial: R, operation: (R, Element) -> R): R =
		operation(initial, this)
}
class CombinedModifier(
    private val outer: Modifier,
    private val inner: Modifier
) : Modifier {
    override fun <R> foldIn(initial: R, operation: (R, Modifier.Element) -> R): R =
        inner.foldIn(outer.foldIn(initial, operation), operation)
}

将包装 modifier inner 和 out 看成指针, modifier 会变成二叉树的结构

A7728D5F-D8EF-4FC8-A7EC-AB03D89C7085.png

在 CombinedModifier 中 foldIn() 并不会执行 operation() ,而是去调用 inner.foldIn() 。如下图 CombinedModifier 对象也可以看成指针的一部分

ED6DCA62-4607-4A39-A152-EA24EE913C95.png

foldIn() 方法的作用是 : 以 inital 为初始值从最内层包装 按照 outer -> inner   的顺序依次使用 modifier 中的每一个 Modifer 对象来执行 operation 函数,并将每次的执行结果作为参数传递到下一个 operation 函数 。

    val str = modifier.foldIn("Start"){  str,element->
        "$str -> ${element.javaClass.simpleName}"
    }
    Log.e(TAG, "foldIn: $str")

foldIn: Start -> SizeModifier -> Background -> PaddingModifier

LayoutNode#setModifier

有了上面的铺垫我们就可以继续 Compose 函数转换成 LayoutNode 中第三步 setModifier 的分析了。

internal class LayoutNode : Measurable, Remeasurement, OwnerScope, LayoutInfo, ComposeUiNode {   
        //set modifier 相关   
	internal val innerLayoutNodeWrapper: LayoutNodeWrapper = InnerPlaceable(this)
  
	private val outerMeasurablePlaceable = OuterMeasurablePlaceable(this, innerLayoutNodeWrapper)  
  
	override var modifier: Modifier = Modifier    
  		set(value) {   
            if (value == field) return
            if (modifier != Modifier) {
                require(!isVirtual) { "Modifiers are not supported on virtual LayoutNodes" }
            }
            field = value         
            //......  
            // innerLayoutNodeWrapper 为初始值,foldOut 从最外层 inner-> outer 的顺序遍历 modifier 
            val outerWrapper = modifier.foldOut(innerLayoutNodeWrapper) { mod, toWrap ->
                var wrapper = toWrap
				//...... 
                val delegate = reuseLayoutNodeWrapper(mod, toWrap)
                if (delegate != null) {
                    //......
                } else {
                     //......
                     //根据不同的类型将 modifier 与 wrapper 包装成  DelegatingLayoutNodeWrapper<T : Modifier.Element>  对象 
                    if (mod is LayoutModifier) {
                        wrapper = ModifiedLayoutNode(wrapper, mod).assignChained(toWrap)
                    }
                    //......
                }
                wrapper
            }
            outerWrapper.wrappedBy = parent?.innerLayoutNodeWrapper
            //将包装了 modifier 的 outerWrapper 对象 赋值给 outerMeasurablePlaceable.outerWrapper
            outerMeasurablePlaceable.outerWrapper = outerWrapper                                                                       
        	//......  
        } 
}

54B2FDF4-EB18-4A37-B4DE-94135654EDA2.png LayoutNode#setModifier

  1. 以 innerLayoutNodeWrapper 为初始值遍历 modifier 将每个 Modifier 对象转换成 LayoutNodeWrapper 对象包装起来得到 outerWrapper
  2. 将 outerWrapper 赋值给 outerMeasurablePlaceable.outerWrapper

InnerPlaceable、 OuterMeasurablePlaceable 、ModifiedLayoutNode:DelegatingLayoutNodeWrapper 都实现了 measure() 方法,相关内容我们下一节介绍。