Flutter 框架跨平台鸿蒙开发——Framework层Rendering子系统详解
Rendering子系统通过布局约束系统和增量更新机制,实现了高效的UI渲染。|| 概念 | 核心思想 | 关键收益 |布局约束| 父约束子 | 简化布局逻辑 |增量布局| 只更新变化部分 | 提升布局性能 |增量绘制| 只绘制变化部分 | 提升绘制性能 || 真正渲染对象 | 高效渲染 |图层隔离| RepaintBoundary | 隔离重绘区域 |

知识点概况
Rendering子系统是Flutter Framework层的渲染引擎核心,负责管理RenderObject树、执行布局和绘制操作。它通过布局约束系统和增量更新机制,实现了高效的UI渲染。
核心概念速览
| 概念 | 一句话说明 |
|---|---|
| RenderObject | 真正执行渲染工作的对象 |
| 布局约束 | 父节点告诉子节点可以多大 |
| 增量布局 | 只更新需要变化的部分 |
| Paint阶段 | 将内容绘制到画布上 |
| 合成阶段 | 组装图层发送给Engine层 |
一、Rendering子系统架构
Rendering子系统负责协调布局和绘制工作。
1.1 Rendering子系统组成图
Rendering子系统 (Framework层)
↓
├── PipelineOwner (渲染管线管理者)
│ ├── requestLayout() - 请求布局
│ ├── requestPaint() - 请求重绘
│ ├── flushLayout() - 执行布局
│ └── flushPaint() - 执行绘制
│
├── RenderObject (渲染对象基类)
│ ├── RenderBox - 盒子模型
│ ├── RenderSliver - 滚动模型
│ ├── RenderView - 根节点
│ └── RenderCustomPaint - 自定义绘制
│
├── 布局系统
│ ├── Constraints - 约束对象
│ ├── performLayout() - 执行布局
│ ├── markNeedsLayout() - 标记需要布局
│ └── BoxConstraints - 盒子约束
│
└── 绘制系统
├── Canvas - 画布
├── Paint - 画笔
├── PictureRecorder - 图片录制器
└── markNeedsPaint() - 标记需要重绘
1.2 Rendering核心职责表
|| 职责 | 核心类 | 主要方法 | 作用 |
|------|--------|----------|------|
| 布局管理 | PipelineOwner, RenderObject | performLayout() | 计算尺寸和位置 |
| 绘制管理 | PipelineOwner, Canvas | paint() | 绘制内容 |
| 约束管理 | Constraints | constrain() | 限制子节点尺寸 |
| 增量更新 | RenderObject | markNeedsLayout/MarkNeedsPaint | 优化渲染性能 |
二、布局约束系统
布局约束是Flutter布局机制的核心。
2.1 约束类型表
|| 约束类型 | 构造方法 | 特点 | 使用场景 |
|---------|----------|------|----------|
| 紧约束 | tight(Size size) | 固定尺寸 | 文本、图片 |
| 松约束 | loose(Size size) | 最大尺寸 | 容器、间距 |
| 扩展约束 | expand() | 填充父容器 | 全屏组件 |
| 无边约束 | unconstrained() | 无限制 | 绝对定位 |
2.2 约束传递流程图
父 RenderObject
↓
┌─────────────────────────────────────┐
│ performLayout() 执行 │
│ - 传递约束给子节点 │
│ - BoxConstraints( │
│ minWidth: 0, │
│ maxWidth: 400, │
│ minHeight: 0, │
│ maxHeight: 600 │
│ ) │
└──────────────┬──────────────────────┘
↓
子 RenderObject
↓
┌─────────────────────────────────────┐
│ performLayout() 执行 │
│ - 接收父节点约束 │
│ - 根据约束计算自己的尺寸 │
│ - size = constraints.constrain( │
│ Size(200, 300) │
│ ) │
│ - 返回尺寸给父节点 │
└──────────────┬──────────────────────┘
↓
父 RenderObject
↓
┌─────────────────────────────────────┐
│ 获知子节点尺寸 │
│ - 设置子节点位置 │
│ - parentData.offset = Offset( │
│ 50, 50 │
│ ) │
└─────────────────────────────────────┘
2.3 BoxConstraints示例
// 紧约束 - 固定尺寸
BoxConstraints tight(Size size) {
return BoxConstraints(
minWidth: size.width,
maxWidth: size.width,
minHeight: size.height,
maxHeight: size.height,
);
}
// 松约束 - 最大尺寸
BoxConstraints loose(Size size) {
return BoxConstraints(
minWidth: 0,
maxWidth: size.width,
minHeight: 0,
maxHeight: size.height,
);
}
// 扩展约束 - 填充父容器
BoxConstraints expand({double? width, double? height}) {
return BoxConstraints(
minWidth: width ?? double.infinity,
maxWidth: width ?? double.infinity,
minHeight: height ?? double.infinity,
maxHeight: height ?? double.infinity,
);
}
三、RenderObject类型体系
Flutter提供多种RenderObject类型满足不同需求。
3.1 RenderObject类型层次图
RenderObject (抽象基类)
↓
├── RenderBox (盒子模型)
│ ├── 二维布局系统
│ ├── 约束: BoxConstraints
│ └── 示例: RenderPadding, RenderOpacity
│
├── RenderSliver (滚动模型)
│ ├── 滚动视图专用
│ ├── 增量渲染
│ └── 示例: RenderSliverList, RenderSliverGrid
│
├── RenderView (根节点)
│ ├── 整个渲染树的根
│ ├── 管理全局变换
│ └── 管理整个屏幕
│
├── RenderAbstractViewport (视口)
│ ├── 管理滚动视口
│ ├── 处理滚动事件
│ └── 示例: RenderViewport
│
└── RenderCustomPaint
├── 自定义绘制
├── 提供Canvas
└── 示例: CustomPaint
3.2 RenderBox vs RenderSliver对比表
|| 特性 | RenderBox | RenderSliver |
|------|-----------|--------------|
| 布局模型 | 二维盒子 | 滚动轴 |
| 适用场景 | 普通布局 | 滚动视图 |
| 布局方式 | 父子约束 | 约束+剩余空间 |
| 性能 | 一次性布局 | 增量渲染 |
| 示例 | Padding, Align | SliverList, SliverGrid |
四、布局流程详解
布局流程是RenderObject计算尺寸和位置的过程。
4.1 布局流程表
|| 阶段 | 方法 | 作用 | 触发条件 |
|------|------|------|----------|
| 1 | markNeedsLayout() | 标记需要布局 | 尺寸或约束变化 |
| 2 | scheduleLayout() | 调度布局任务 | PipelineOwner管理 |
| 3 | flushLayout() | 执行所有布局任务 | 帧回调中 |
| 4 | performLayout() | 计算尺寸和位置 | 遍历dirty的RenderObject |
4.2 布局流程详细图
┌─────────────────────────────────────────────┐
│ markNeedsLayout() - 标记需要布局 │
│ - 标记RenderObject为needsLayout │
│ - 请求PipelineOwner执行布局 │
└───────────────┬───────────────────────────┘
↓
┌─────────────────────────────────────────────┐
│ PipelineOwner.flushLayout() │
│ - 遍历needsLayout的RenderObject │
│ - 按深度优先顺序遍历 │
└───────────────┬───────────────────────────┘
↓
┌─────────────────────────────────────────────┐
│ performLayout() - 执行布局 │
│ 1. 接收父节点约束 │
│ 2. 根据约束计算自己的尺寸 │
│ 3. 传递约束给子节点 │
│ 4. 遍历子节点 │
│ 5. 子节点返回尺寸 │
│ 6. 设置子节点位置 │
└───────────────┬───────────────────────────┘
↓
┌─────────────────────────────────────────────┐
│ 布局完成 │
│ - 所有RenderObject已计算尺寸 │
│ - 所有RenderObject已设置位置 │
└─────────────────────────────────────────────┘
4.3 performLayout()示例
class RenderCustomBox extends RenderBox {
void performLayout() {
// 1. 接收父节点约束
BoxConstraints constraints = this.constraints;
// 2. 根据约束计算自己的尺寸
Size size = constraints.constrain(
Size(100, 100), // 期望的尺寸
);
// 3. 设置自己的尺寸
this.size = size;
// 4. 传递约束给子节点
if (child != null) {
child!.layout(constraints);
}
}
}
五、绘制流程详解
绘制流程是将内容绘制到画布的过程。
5.1 绘制流程表
|| 阶段 | 方法 | 作用 | 触发条件 |
|------|------|------|----------|
| 1 | markNeedsPaint() | 标记需要绘制 | 内容变化 |
| 2 | schedulePaint() | 调度绘制任务 | PipelineOwner管理 |
| 3 | flushPaint() | 执行所有绘制任务 | 帧回调中 |
| 4 | paint() | 绘制内容到画布 | 遍历dirty的RenderObject |
5.2 绘制流程详细图
┌─────────────────────────────────────────────┐
│ markNeedsPaint() - 标记需要绘制 │
│ - 标记RenderObject为needsPaint │
│ - 请求PipelineOwner执行绘制 │
└───────────────┬───────────────────────────┘
↓
┌─────────────────────────────────────────────┐
│ PipelineOwner.flushPaint() │
│ - 创建PictureRecorder │
│ - 遍历needsPaint的RenderObject │
└───────────────┬───────────────────────────┘
↓
┌─────────────────────────────────────────────┐
│ paint() - 执行绘制 │
│ 1. 创建Canvas │
│ 2. 绘制背景 │
│ 3. 绘制子节点 │
│ 4. 绘制装饰 │
└───────────────┬───────────────────────────┘
↓
┌─────────────────────────────────────────────┐
│ 生成Picture对象 │
│ - 记录所有绘制操作 │
│ - 发送给Engine层 │
└─────────────────────────────────────────────┘
5.3 paint()示例
class RenderCustomBox extends RenderBox {
void paint(PaintingContext context, Offset offset) {
// 1. 获取Canvas
Canvas canvas = context.canvas;
// 2. 绘制背景
Paint paint = Paint()
..color = Colors.blue
..style = PaintingStyle.fill;
canvas.drawRect(
Rect.fromLTWH(offset.dx, offset.dy, size.width, size.height),
paint,
);
// 3. 绘制子节点
if (child != null) {
context.paintChild(child!, offset);
}
}
}
六、增量渲染优化
Rendering子系统通过增量更新优化性能。
6.1 增量优化策略表
|| 优化策略 | 问题 | 解决方案 | 性能提升 |
|---------|------|----------|----------|
| 增量布局 | 全量重新布局 | 只布局dirty的节点 | 40-60% ↑ |
| 增量绘制 | 全量重新绘制 | 只绘制dirty的节点 | 50-70% ↑ |
| 图层隔离 | 连锁重绘 | RepaintBoundary | 30-50% ↑ |
| 布局边界 | 深度遍历 | LayoutBoundary | 20-30% ↑ |
6.2 RepaintBoundary使用示例
// 不使用RepaintBoundary - 整个树重绘
class BadExample extends StatelessWidget {
Widget build(BuildContext context) {
return Column(
children: [
Container(color: Colors.red, height: 100), // 重绘
Container(color: Colors.blue, height: 100), // 重绘
Container(color: Colors.green, height: 100), // 重绘
],
);
}
}
// 使用RepaintBoundary - 隔离重绘
class GoodExample extends StatelessWidget {
Widget build(BuildContext context) {
return Column(
children: [
const RepaintBoundary(
child: Container(color: Colors.red, height: 100),
), // 独立重绘
const RepaintBoundary(
child: Container(color: Colors.blue, height: 100),
), // 独立重绘
const RepaintBoundary(
child: Container(color: Colors.green, height: 100),
), // 独立重绘
],
);
}
}
七、Rendering子系统示例演示
本示例展示了Rendering子系统的核心机制。
7.1 示例功能说明
演示内容:
├─ 渲染统计面板
│ ├─ 布局次数
│ ├─ 绘制次数
│ └─ 事件记录数
│
├─ 布局约束系统演示
│ ├─ tight()紧约束
│ ├─ loose()松约束
│ └─ expand()扩展约束
│
├─ RenderObject类型展示
│ ├─ RenderBox盒子模型
│ ├─ RenderSliver滚动模型
│ ├─ RenderCustomPaint自定义绘制
│ └─ RenderView根节点
│
└─ 布局和绘制流程演示
├─ performLayout()流程
└─ paint()流程
7.2 运行示例项目
# 进入项目目录
cd flutter_examples/framework_architecture_demo_01_3
# 运行应用
flutter run -d chrome
7.3 核心渲染示例代码
// 布局流程示例
class LayoutExample extends StatelessWidget {
Widget build(BuildContext context) {
return ConstrainedBox(
// 传递约束给子节点
constraints: BoxConstraints(
minWidth: 100,
maxWidth: 400,
minHeight: 100,
maxHeight: 400,
),
child: Container(
// 子节点根据约束计算尺寸
color: Colors.blue,
),
);
}
}
// 绘制流程示例
class PaintExample extends StatelessWidget {
Widget build(BuildContext context) {
return CustomPaint(
painter: MyPainter(),
child: Container(),
);
}
}
class MyPainter extends CustomPainter {
void paint(Canvas canvas, Size size) {
// 执行绘制操作
final paint = Paint()
..color = Colors.blue
..style = PaintingStyle.fill;
canvas.drawCircle(
Offset(size.width / 2, size.height / 2),
size.width / 2,
paint,
);
}
bool shouldRepaint(MyPainter oldDelegate) => false;
}
八、总结
Rendering子系统通过布局约束系统和增量更新机制,实现了高效的UI渲染。
核心要点总结表
|| 概念 | 核心思想 | 关键收益 |
|------|----------|----------|
| 布局约束 | 父约束子 | 简化布局逻辑 |
| 增量布局 | 只更新变化部分 | 提升布局性能 |
| 增量绘制 | 只绘制变化部分 | 提升绘制性能 |
| RenderObject | 真正渲染对象 | 高效渲染 |
| 图层隔离 | RepaintBoundary | 隔离重绘区域 |
Rendering子系统学习路径
┌─────────────┐
│理解约束系统 │ → 掌握布局机制
└──────┬──────┘
↓
┌─────────────┐
│熟悉RenderObject│ → 了解渲染对象
└──────┬──────┘
↓
┌─────────────┐
│掌握布局流程 │ → 优化布局性能
└──────┬──────┘
↓
┌─────────────┐
│熟悉绘制流程 │ → 优化绘制性能
└──────┬──────┘
↓
┌─────────────┐
│增量渲染优化 │ → 提升整体性能
└─────────────┘
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
更多推荐




所有评论(0)