菜单

布局引擎

相关源文件

React Native 布局引擎负责计算 React Native 应用程序中 UI 组件的大小和位置。其核心是 Yoga,一个跨平台的 Flexbox 布局算法实现。本文档将解释 Yoga 的工作原理、核心组件以及布局计算过程。

有关 UI 组件和样式的信息,请参阅 UI 组件和样式。有关特定平台实现的信息,请参阅 Android 实现iOS 实现

Yoga 概述

Yoga 是一个用 C++ 编写的独立布局引擎,实现了 Flexbox 规范。它根据视图的样式属性、约束以及它们在组件层次结构中与其他视图的关系来计算视图的位置和大小。Yoga 使 React Native 能够在 iOS 和 Android 上提供一致的布局体验。

Yoga 的主要特点包括:

  • 完整的 Flexbox 布局实现
  • 支持绝对和相对定位
  • 处理复杂的层次化布局
  • 跨平台独立的布局计算
  • 针对移动设备的性能优化

架构图

来源

核心组件

节点

yoga::Node 类是布局系统的基本构建块。React Native 中的每个视图都对应于布局树中的一个 Yoga 节点。

Node 的关键特征

  • 维护父子关系
  • 存储样式属性
  • 包含计算出的布局信息
  • 可进行测量和布局
├── Node properties
│   ├── Style (positioning, dimensions, margins, etc.)
│   ├── Layout results (final position and size)
│   ├── Children (nested nodes)
│   ├── Config (layout behavior settings)
│   └── Measurement functions (for custom measuring)

来源

风格

yoga::Style 类封装了所有影响布局的样式属性,包括:

  • Flex 属性(方向、增长、收缩、基准值)
  • 尺寸(宽度、高度、最小/最大尺寸)
  • 定位类型(相对、绝对)
  • 间距(外边距、内边距、边框)
  • 对齐(justifyContent、alignItems、alignSelf)

这些属性决定了一个节点及其子节点的布局方式。

来源

LayoutResults

LayoutResults 类存储了节点的计算布局信息

  • 位置(顶部、左侧、右侧、底部)
  • 尺寸(宽度、高度)
  • 外边距、边框和内边距
  • 方向和溢出标志

在布局计算之后,这些值表示 UI 组件的最终位置和大小。

来源

Config

yoga::Config 类包含 Yoga 引擎的配置设置

  • 像素比例因子(用于像素网格对齐)
  • 错误处理设置
  • 实验性功能标志
  • 自定义日志函数

Config 设置会影响布局的计算和渲染方式。

来源

布局计算过程

Yoga 中的布局计算遵循一个多步骤过程,以确定布局树中每个节点的尺寸和位置。

布局计算流程

来源

关键布局步骤

  1. 初始配置:布局过程从使用适当的比例因子和布局方向配置 Yoga 树开始。

  2. 测量阶段:

    • 对于具有自定义测量功能的叶节点(如文本),将调用 `measureNodeWithMeasureFunc()` 函数
    • 对于没有子节点或测量功能的节点,`measureNodeWithoutChildren()` 提供默认测量值
  3. 布局阶段:

    • 对于相对定位的节点,应用 Flex 布局算法
    • 对于绝对定位的节点,`layoutAbsoluteChild()` 根据约束条件计算位置
  4. Flex 布局计算:

    • 计算每个子节点的 flex 基准值
    • 将子节点组织成 flex 行
    • 根据 flex 系数分配可用空间
    • 应用对齐规则(justify-content、align-items)
  5. 完成:

    • 使用最终位置和尺寸更新布局结果
    • 应用舍入以将值吸附到像素网格

来源

Flexbox 实现

Yoga 实现的 CSS Flexbox 规范,并针对移动平台进行了一些调整。核心概念保持不变:

Flex 方向和布局

`FlexDirection` 决定了子节点布局的主要轴

  • Row:从左到右(在 LTR 语言中)
  • Column:从上到下
  • RowReverse:从右到左(在 LTR 语言中)
  • ColumnReverse:从下到上

`FlexDirection` 会影响 `justifyContent` 和 `alignItems` 等其他属性的行为。

来源

Flex 分配

Yoga 根据 Flex 属性在主轴上分配空间

  1. Flex Grow:确定当存在额外空间时,节点相对于兄弟节点增长的程度

  2. Flex Shrink:确定在空间受限时,节点相对于兄弟节点收缩的程度

  3. Flex Basis:节点在增长或收缩之前的初始主尺寸

分配算法实现在 `distributeFreeSpaceFirstPass()` 和 `distributeFreeSpaceSecondPass()` 函数中。

来源

对齐

Yoga 实现了一些对齐属性

  1. Justify Content:在主轴上对齐项目

    • FlexStartCenterFlexEndSpaceBetweenSpaceAroundSpaceEvenly
  2. Align Items:在交叉轴上对齐项目

    • FlexStartCenterFlexEndStretchBaseline
  3. Align Self:允许单个项目覆盖父级的 align-items 设置

对齐逻辑在确定大小和主轴位置后应用。

来源

与 React Native 的集成

布局引擎通过 Shadow Node 树系统与 React Native 集成。

YogaLayoutableShadowNode

YogaLayoutableShadowNode 类充当 React Native 的 Shadow Node 系统与 Yoga 之间的桥梁

  • 继承自 `LayoutableShadowNode`
  • 包含一个 Yoga 节点实例
  • 将 React Native 的样式属性转换为 Yoga 的样式属性
  • 使 Yoga 节点树与 Shadow Node 树同步
  • 触发布局计算并应用结果
├── YogaLayoutableShadowNode
│   ├── yogaNode_ (yoga::Node instance)
│   ├── yogaConfig_ (Yoga configuration)
│   ├── updateYogaProps() (converts React props to Yoga style)
│   ├── updateYogaChildren() (syncs children with Yoga tree)
│   └── layoutTree() (triggers Yoga layout calculation)

来源

React Native 中的布局计算流程

当 React Native 组件需要进行布局时

  1. 会使用布局约束调用 `YogaLayoutableShadowNode::layoutTree()`
  2. 约束被转换为 Yoga 样式
  3. 在根 Yoga 节点上调用了 YGNodeCalculateLayout()
  4. 从 Yoga 节点读取计算出的布局并应用到阴影节点
  5. 然后使用阴影节点的布局来定位原生视图

来源

特殊布局考虑

绝对定位

当节点具有 position: 'absolute' 时,它将脱离文档流,并根据其相对于包含块的约束(上、左、下、右)进行定位。

layoutAbsoluteChild() 函数

  • 根据约束计算子节点尺寸
  • 将子节点相对于其容器定位
  • 处理子节点具有宽高比的情况

来源

基线对齐

当使用 alignItems: 'baseline' 时,子项将对齐,使其文本基线匹配。这对于不同大小的文本尤其有用。

calculateBaseline() 函数

  • 查找节点的基线
  • 对于具有基线函数的节点,调用该函数
  • 对于其他节点,查找第一个子节点并使用其基线

来源

像素网格对齐

为了确保屏幕上清晰的渲染,布局值会与像素网格对齐

  • roundLayoutResultsToPixelGrid() 处理整个布局树
  • 值根据设备的像素比例因子进行舍入
  • 为文本组件提供了特殊处理以防止截断

来源

常用布局属性及其影响

属性描述对布局的影响
flexDirection主轴方向决定了项目的流动方向
justifyContent主轴上的对齐在主轴上对齐项目
alignItems交叉轴上的对齐在垂直于主轴的方向上定位项目
flexGrow增长能力按比例占用可用空间
flexShrink收缩能力在受到约束时按比例释放空间
flexBasis初始主尺寸增长/收缩前的起始尺寸
position定位模式'relative'(默认)或 'absolute'
width/height尺寸如果指定了则为固定尺寸
margin节点周围的空间在节点边框外创建空间
padding节点内部的空间在节点边框内创建空间

来源

性能考量

Yoga 包含多项优化以提高布局性能

  1. 布局缓存:避免对未更改的节点重新计算布局
  2. 增量布局:仅重新计算树中受影响的分支
  3. 脏传播:当节点更改时,仅将其及其祖先标记为脏
  4. 配置版本控制:跟踪配置更改何时使缓存的布局失效

这些优化对于维持流畅的用户界面性能至关重要,尤其是在处理复杂或深度嵌套的布局时。

来源