Flutter / RN / iOS 的 UI 渲染机制,本质差异在哪里?


网罗开发 (小红书、快手、视频号同名)

大家好,我是 展菲,目前在上市企业从事人工智能项目研发管理工作,平时热衷于分享各种编程领域的软硬技能知识以及前沿技术,包括iOS、前端、Harmony OS、Java、Python等方向。在移动端开发、鸿蒙开发、物联网、嵌入式、云原生、开源等领域有深厚造诣。

图书作者:《ESP32-C3 物联网工程开发实战》
图书作者:《SwiftUI 入门,进阶与实战》
超级个体:COC上海社区主理人
特约讲师:大学讲师,谷歌亚马逊分享嘉宾
科技博主:华为HDE/HDG

我的博客内容涵盖广泛,主要分享技术教程、Bug解决方案、开发工具使用、前沿科技资讯、产品评测与使用体验 。我特别关注云服务产品评测、AI 产品对比、开发板性能测试以及技术报告,同时也会提供产品优缺点分析、横向对比,并分享技术沙龙与行业大会的参会体验。我的目标是为读者提供有深度、有实用价值的技术洞察与分析。

展菲:您的前沿技术领航员

👋 大家好,我是展菲!

📱 全网搜索"展菲",即可纵览我在各大平台的知识足迹。

📣 公众号"Swift社区",每周定时推送干货满满的技术长文,从新兴框架的剖析到运维实战的复盘,助您技术进阶之路畅通无阻。

💬 微信端添加好友"fzhanfei",与我直接交流,不管是项目瓶颈的求助,还是行业趋势的探讨,随时畅所欲言。

📅 最新动态:2025 年 3 月 17 日

快来加入技术社区,一起挖掘技术的无限潜能,携手迈向数字化新征程!

文章目录

    • 前言
    • [先从一张"脑补图"理解三种 UI 渲染模型](#先从一张“脑补图”理解三种 UI 渲染模型)
      • [Flutter 的渲染模型](#Flutter 的渲染模型)
      • [React Native 的渲染模型](#React Native 的渲染模型)
      • [iOS 原生(UIKit / SwiftUI)](#iOS 原生(UIKit / SwiftUI))
    • [Flutter 为什么滚动特别稳?](#Flutter 为什么滚动特别稳?)
      • [Flutter 的滚动是"纯本地逻辑"](#Flutter 的滚动是“纯本地逻辑”)
      • [Flutter 为什么首屏反而偏慢?](#Flutter 为什么首屏反而偏慢?)
    • [RN 在复杂场景下为什么容易掉帧?](#RN 在复杂场景下为什么容易掉帧?)
      • [一个最典型的 RN 动画场景](#一个最典型的 RN 动画场景)
      • [useNativeDriver 是"止痛药",不是解药](#useNativeDriver 是“止痛药”,不是解药)
    • [Web / RN 为什么对"原生一致性"这么敏感?](#Web / RN 为什么对“原生一致性”这么敏感?)
      • [Flutter 为什么反而"样式一致"?](#Flutter 为什么反而“样式一致”?)
    • [iOS 原生的性能天花板在哪里?](#iOS 原生的性能天花板在哪里?)
    • 三种方案放在真实项目里的取舍
    • 总结

前言

如果你同时写过 Flutter、RN 和 iOS 原生,大概率会有一种直觉:

  • Flutter 滚动是真的稳
  • RN 页面一复杂就开始抖
  • iOS 原生性能最好,但人力成本也是真的高

问题是------
为什么会这样?

不是因为语言,不是因为团队水平,而是三者从 UI 渲染这一步开始,走的就是完全不同的路

这篇文章我们就从「UI 是怎么画出来的」这个最底层的点出发,把三种方案真正的差异讲清楚。

先从一张"脑补图"理解三种 UI 渲染模型

我们先不急着看代码,先把三种方案在脑子里"画"出来。

Flutter 的渲染模型

复制代码
Dart Widget Tree
        ↓
RenderObject Tree
        ↓
Skia
        ↓
GPU

特点只有一句话:

Flutter 不使用系统原生 UI 控件,而是自己画。

按钮、列表、文本、动画,本质都是 Skia 在一块画布上画出来的。

React Native 的渲染模型

复制代码
JS (React)
   ↓
Bridge
   ↓
Native UI View (UIKit / Android View)

RN 的核心思路是:

UI 还是原生的,但"怎么组合 UI"交给 JS。

问题也恰恰出在这个 Bridge 上。

iOS 原生(UIKit / SwiftUI)

复制代码
Swift / ObjC
   ↓
UIKit / SwiftUI
   ↓
Core Animation
   ↓
GPU

没有跨语言,没有中间层,
系统怎么设计,开发者就怎么用。

如果你只记住一句话:

  • Flutter:自己画
  • RN:JS 指挥原生画
  • iOS:直接画

后面所有性能差异,其实都能推出来。

Flutter 为什么滚动特别稳?

很多人第一次写 Flutter ListView,都会有点震惊:

怎么随便写写,滚动就这么顺?

原因其实非常直接。

Flutter 的滚动是"纯本地逻辑"

在 Flutter 里,一个滚动列表大概是这样:

dart 复制代码
ListView.builder(
  itemCount: 1000,
  itemBuilder: (context, index) {
    return ListTile(
      title: Text('Item $index'),
    );
  },
);

关键点不在 Widget,而在底层:

  • 手势处理在 Dart 层
  • 滚动计算在 Dart 层
  • 帧同步直接对接 Skia

整个滚动过程,不需要跨语言通信。

这意味着什么?

意味着:

  • 没有 JS 卡顿影响滚动
  • 没有 Bridge 延迟
  • 掉帧风险极低

Flutter 为什么首屏反而偏慢?

但 Flutter 也不是没有代价。

首屏慢,原因通常有三类:

  • Dart VM / AOT 启动
  • Widget Tree 构建成本
  • Skia Pipeline 初始化

你可以理解为:

Flutter 是"先把画室搭好,再开始画"。

一旦跑起来,后面就很稳;

但启动那一下,成本是实打实存在的。

RN 在复杂场景下为什么容易掉帧?

RN 的问题,其实不是"慢",而是不可控

一个最典型的 RN 动画场景

jsx 复制代码
Animated.timing(this.state.x, {
  toValue: 100,
  duration: 300,
  useNativeDriver: false,
}).start();

如果 useNativeDriver: false

  • 每一帧动画
  • 都需要 JS 计算
  • 再通过 Bridge 通知原生更新 View

这意味着什么?

复制代码
16ms 内:
JS 算 → Bridge → Native → Render

只要其中任意一环慢一点:

  • JS 被阻塞
  • Bridge 堆积
  • 原生掉帧

你看到的结果就是:
动画一卡一卡的,但你很难定位是哪一层的问题。

useNativeDriver 是"止痛药",不是解药

开启 native driver 后,动画会交给原生跑:

jsx 复制代码
useNativeDriver: true

但代价是:

  • 只能用 transform / opacity
  • 无法驱动 layout
  • 复杂交互依然要回到 JS

这也是为什么 RN 在:

  • 复杂列表联动
  • 大量手势动画
  • 高并发 UI 更新

这些场景下,很容易到瓶颈。

Web / RN 为什么对"原生一致性"这么敏感?

这一点,做过多端适配的人体会会非常深。

RN 和 Web 的 UI,本质是:

对系统控件的"再封装"。

这会带来几个现实问题:

  • iOS 和 Android 原生控件行为不同
  • 系统版本升级会影响样式
  • 某些 UI bug 只在某个平台出现

你明明写的是一套 JS / CSS,

但最后却要:

  • iOS 单独 patch
  • Android 单独 hack

Flutter 为什么反而"样式一致"?

因为 Flutter 根本没用系统控件。

  • 按钮自己画
  • 文本自己排
  • 阴影、圆角全自己算

代价是包体和启动时间,

收益是:

UI 行为在所有平台几乎一致。

iOS 原生的性能天花板在哪里?

从纯性能角度看:

iOS 原生几乎没有对手。

一个典型的 UIKit 列表:

swift 复制代码
class ViewController: UIViewController, UITableViewDataSource {
    func tableView(_ tableView: UITableView,
                   numberOfRowsInSection section: Int) -> Int {
        return 1000
    }

    func tableView(_ tableView: UITableView,
                   cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = UITableViewCell()
        cell.textLabel?.text = "Row \(indexPath.row)"
        return cell
    }
}

系统级优化包括:

  • 视图复用
  • Core Animation 合成
  • RunLoop 调度

这些都是 Flutter 和 RN 无法直接复刻的系统能力

那为什么大家还在做跨端?

答案只有一个:人力成本

  • 三端三套代码
  • 三个技术栈
  • 三种问题模型

在业务快速迭代期,这个成本非常高。

所以真实世界的选择往往是:

  • 极致体验 → 原生
  • 体验和效率平衡 → Flutter
  • 强动态 / 业务驱动 → RN / Web

三种方案放在真实项目里的取舍

如果你站在一个负责人视角,而不是"技术选型洁癖",结论通常会是这样:

  • 强动画、重交互、长期维护:Flutter
  • 快速试错、动态下发、业务变化快:RN
  • 系统级能力、极致性能、平台特性:iOS 原生

没有银弹,只有边界。

总结

很多技术争论,本质不是对错,而是上下文不同

Flutter、RN、iOS 原生三套方案:

  • 起点不同
  • 设计目标不同
  • 解决的问题也不同

真正成熟的判断标准只有一个:

这个项目最怕什么?

  • 怕卡顿 → 远离 Bridge
  • 怕成本 → 拥抱跨端
  • 怕体验 → 回归原生

想清楚这个问题,选型其实就没那么纠结了。

相关推荐
茅根竹蔗水__11 小时前
iOS应用(App)生命周期、视图控制器(UIViewController)生命周期和视图(UIView)生命周期
ios
leiming611 小时前
c++ QT 开发第二天,用ui按钮点亮实体led
开发语言·qt·ui
kirk_wang12 小时前
Flutter环境搭建与项目创建详解
flutter·移动开发·跨平台
西西学代码13 小时前
Flutter---动画
flutter
码农汉子14 小时前
构建属于自己的Flutter混合开发框架
flutter·dart
技术小甜甜14 小时前
【Godot】【入门】信号系统从 0 到 1(UI/玩法彻底解耦的通用写法)
ui·游戏引擎·godot
毛发浓密的女猴子14 小时前
SSE Connect 数据解析详解
ios
特立独行的猫a15 小时前
Docker 管理利器:docker-compose-ui 与 Portainer 详解
运维·ui·docker·容器·portainer
JAVA+C语言16 小时前
iOS App小组件(Widget)显示LottieFiles动画
ios