Compose 渲染内核 (4):LayoutNode —— UI 树的硬核骨架

47 阅读2分钟

前言

我们在前面几篇中讨论了组合阶段生成的 Slot Table。但真正参与测量、排版和交给 Skia 绘制的“实体”是什么?

它就是 LayoutNode。今天我们来深度对比它与传统 View 的差异。


一、 LayoutNode vs View.java

作为一个十年老兵,你可能对 android.view.View 的 3 万行源码记忆犹新。LayoutNode 是 Compose 时代的对应物,但它实现了彻底的“功能剥离”。

特性View.javaLayoutNode
职责状态管理、触摸、绘制、测量、动画全包仅负责几何结构(测量与位置)
层级必须继承组合优于继承
状态持有内部持有各种私有变量状态存储在外部的 Slot Table 中

二、 LayoutNode 的生命周期

  1. 挂载 (Attached):由 Applier 将其插入到节点树中。
  2. 测量 (Remeasured):当父约束变动或子项触发重绘。
  3. 布局 (Relayout):确定 offset
  4. 绘制 (Redrawn):生成绘制指令流。

三、 核心链路:MeasurePolicy 的调度

LayoutNode 内部持有一个 MeasurePolicy

  • 当你调用 Modifier.layout 时,其实是在为这个 LayoutNode 动态注入测量逻辑。
  • 它严格遵守 “Parent-Child”单向约束协议

四、 秘密武器:Owner 接口

LayoutNode 并不直接与 Android 系统打交道。它通过一个名为 Owner 的接口(在 Android 上的具体实现是 AndroidComposeView)与外界通信。

  • Owner 的职责
    • 接收系统的点击事件,并分发给正确的 LayoutNode
    • 管理无效化(Invalidation)区域。
    • 触发最终的 Canvas 绘制。

五、 给十年老兵的架构启示

  1. 节点轻量化:由于 LayoutNodeView 轻得多,这解释了为什么我们可以肆无忌惮地使用 BoxColumn 来美化代码结构,而不用担心对象创建开销。
  2. 树的操作是昂贵的:虽然 LayoutNode 轻量,但频繁的树结构变动(如不恰当的 if/else 显隐切换)依然会导致 Slot Table 和节点树的大规模重构。

🏗️ 源码关键点

  • androidx.compose.ui.node.LayoutNode
  • androidx.compose.ui.node.InnerNodeCoordinator
  • androidx.compose.ui.platform.AndroidComposeView

结语

LayoutNode 是逻辑与像素之间的最后一道防线。它只管几何,不管逻辑,这种纯粹性赋予了 Compose 极速排版的能力。

下一篇,我们将进入图形学领域,研究 DrawScope 与 GraphicsLayer 的加速奥秘