| 阶段 | 核心分工 | 触发条件 | 优化思路 |
|---|
| 重组(Compose) | 构建 / 更新 UI 内容 / 结构 | 内容 / 结构类状态变化(如文字、列表项数) | 细粒度重组(仅受影响组件执行) |
| 布局(Layout) | 计算 UI 位置 / 尺寸 | 位置 / 尺寸类状态变化(如偏移、滚动、尺寸) | 延迟读取位置状态 → 跳过重组,仅触发布局 |
| 绘制(Draw) | 将 UI 渲染到屏幕 | 内容 / 位置 / 尺寸任一变化(或缓存失效) | 绘制缓存 → 无变化时复用绘制结果 |
一、Flutter 的渲染流程也分为三个核心阶段,和 Compose 逻辑高度对齐(因为都是声明式 UI):
| Flutter 阶段 | 对应 Compose 阶段 | 核心分工 | 触发条件 |
|---|
| Build(构建) | 重组(Composition) | 执行 build() 方法,生成 Widget 树 → Element 树 | 状态变化(如 setState、Provider 数据更新) |
| Layout(布局) | Layout(布局) | 执行 RenderObject 的 performLayout(),计算尺寸 / 位置 | Widget/Element 变化导致尺寸 / 位置改变,或布局参数(如 Padding、Positioned)变化 |
| Paint(绘制) | Draw(绘制) | 执行 RenderObject 的 paint(),将内容绘制到画布 | Build/Layout 阶段导致内容 / 位置 / 尺寸变化 |
关键差异:
- Flutter 的
Build 阶段是 “重新执行 build() 方法”,等价于 Compose 的 “重组”; - Flutter 中 “延迟布局阶段读取状态” 的思路也存在(比如用
AnimatedPositioned 控制位置,仅触发布局而非全量 build)。
二、kotlin remember mutableStateOf和flutter State以及Vue Ref之间的相似好区别。
1. 核心共性(响应式的本质)
| 特性 | Compose MutableState | Flutter State | Vue Ref |
|---|
| 核心目标 | 数据驱动 UI 重组 | 数据驱动 Widget 重建 | 数据驱动 DOM 更新 |
| 可观察性 | 内置(值变触发重组) | 需通过 setState 触发重建 | 内置(值变触发依赖收集 + 更新) |
| 状态封装 | 包裹单个值(value 属性) | 封装组件状态(类成员) | 包裹单个值(value 属性) |
| 基础用法 | var a by mutableStateOf(0) | int _a = 0; setState(() => _a++); | const a = ref(0); a.value++ |
2. 关键差异(框架理念导致)
| 维度 | Compose MutableState | Flutter State | Vue Ref |
|---|
| 状态归属 | 「无组件绑定」:状态是独立对象,仅通过 remember 绑定组件生命周期 | 「强组件绑定」:State 是 StatefulWidget 的专属内部类,与组件一一对应 | 「无绑定」:全局 / 局部皆可,通过「依赖收集」关联视图 |
| 触发更新的方式 | 自动:修改 value 即触发重组(Compose 自动追踪依赖) | 手动:必须调用 setState 标记状态变化,触发 Widget 重建 | 自动:修改 value 触发更新(Vue 自动收集 Ref 依赖的视图) |
| 持久化规则 | 需手动用 remember/rememberSaveable 避免重组重置 | 天然随 State 实例持久化(组件不销毁则状态保留) | 天然持久化(除非 Ref 被销毁) |
| 适用粒度 | 细粒度(单个值) | 粗粒度(组件级,setState 触发整个组件重建) | 细粒度(单个值) |
补充:容易混淆的延伸点
-
核心结论:这三者都是响应式编程中「状态封装 + 自动更新 UI」的基础方案,差异仅源于框架的「组件模型」和「更新机制」设计:
- Flutter 是「组件级手动触发更新」;
- Compose 是「值级自动触发更新 + 需手动持久化」;
- Vue 是「值级自动触发更新 + 天然持久化 + 自动依赖收集」。
三、布局父子间的约束(compose、flex、flutter、盒式布局的差异)
| 布局体系 | 核心逻辑 | 控制权归属 | 尺寸执行顺序 | 典型标识属性 |
|---|
| 原生 Android Widget | 子自主定尺寸,父按流排位置 | 子元素主导 | 子定尺寸 → 父按尺寸排 / 适配 | 子:layout_width/wrap_content |
| CSS 普通布局(block/inline) | 子自主定尺寸,父按文档流排位置 | 子元素主导 | 子定尺寸 → 父按尺寸排 / 适配 | 子:width/height/margin |
| Compose 布局 | 父定约束,子在约束内适配 | 父容器主导 | 父定约束 → 子适配约束 | 父:fillMaxWidth;子:fillMax* |
| CSS Flex/Grid 布局 | 父定 flex/grid 规则,子按规则适配 | 父容器主导 | 父定规则 → 子适配规则 | 父:display: flex/grid;子:flex:1 |
| Flutter 布局 | 父定布局规则 / 约束,子适配父约束 | 父容器主导 | 父定约束 → 子适配约束 | 父:Expanded/Container;子:Flexible |
总结:comopse与css flex(Flexible Box) 都是弹性布局,父约束子类。而传统的盒式布局就是子类决定父类组件。