在这里插入图片描述

知识点概况

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

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐