认真对待每时、每刻每一件事,把握当下、立即去做。

Flutter UI 性能优化实践经验,结合关键优化方向和具体代码示例进行一个解析。

一. 布局优化

1. 减少布局计算‌

使用 ListView.builder 实现懒加载,只构建可见项,避免一次性计算所有子项布局。同时要注意避免在 Column 中嵌套 ListView 导致布局冲突:

//   错误写法
Column(children: [
Header(),
ListView(children: items.map((e) => Item(e)).toList())
]) // 正确写法
Column(children: [
Header(),
Expanded(child: ListView.builder(itemCount: items.length))
])

2. 分帧渲染

2.1 分帧渲染解析

对复杂卡片采用分帧构建策略,这里说的是过渡帧,本质上会增加总渲染时间,但改善了感知性能提升体验。

bool _showRealContent = false;
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
setState(() => _showRealContent = true); // 下一帧加载真实内容
});
}
Widget build(BuildContext context) => _showRealContent ? _buildReal() : _buildPlaceholder();

addPostFrameCallback 工作原:WidgetsBinding.instance.addPostFrameCallback 会在当前帧绘制完成后执行回调函数,且回调只执行一次。

分帧渲染的本质是将原本可能超过 16.6ms 的构建任务拆解为多个子任务,分散到连续帧中执行。例如,对长列表的逐项渲染或复杂动画的分步计算。而示例中的“过渡帧”仅通过占位符延迟真实内容加载,属于视觉优化手段,未实际拆分构建任务。

用户代码通过 _showRealContent 控制占位符与真实内容的切换,仅减少首帧的构建压力,但若 _buildReal() 本身耗时仍超过 16.6ms,依然会引发卡顿。真正的分帧渲染需结合 Future.delayedcompute 隔离计算或 ListView.builder 的懒加载机制。

2.2 分帧渲染实现
2.2.1 使用 Future.delayed 分帧渲染

通过将任务拆分为多个异步帧执行,避免主线程阻塞:

Future<void> _loadDataInFrames(List<Widget> widgets) async {
for (var i = 0; i < widgets.length; i++) {
await Future.delayed(Duration(milliseconds: 16)); // 约60fps的帧间隔
setState(() {
_visibleWidgets.add(widgets[i]); // 逐帧添加Widget到界面
});
}
}

特点‌:

  • 适用于顺序加载大量小部件;
  • 需手动控制帧间隔时间,避免过快导致卡顿。
2.2.2 使用 compute 隔离计算

将耗时计算放到隔离线程,完成后分帧更新 UI:

// 定义耗时计算函数(需为顶级函数或静态方法)
static int _heavyCalculation(int input) {
return input * 2; // 模拟复杂计算
} // 在UI线程调用
void _startCalculation() async {
final result = await compute(_heavyCalculation, 1000000);
setState(() => _result = result); // 计算完成后更新UI
}

特点‌:

  • 适合 CPU 密集型任务(如 JSON 解析、图像处理)。
  • 需注意数据序列化限制(不能传递闭包或非基本类型)。
2.2.3 ListView.builder 懒加载机制

自动按需渲染可见区域的子项:

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

优化技巧‌:

  • 结合 itemExtent 固定子项高度提升性能。
  • 复杂子项使用 RepaintBoundary 隔离重绘。
2.2.4 其他分帧渲染方法

Keframe 组件库

FrameSeparateWidget(
child: YourComplexWidget(), // 包裹复杂组件
)

效果‌:自动拆分组件树为多帧渲染,卡顿减少50%。

2.2.4 综合建议
  • 轻量级任务‌:优先用 Future.delayed
  • 计算密集型‌:选择 compute 或 Isolate。
  • 长列表‌:ListView.builder + RepaintBoundary
  • 复杂页面‌:集成 Keframe 组件。

3. RelayoutBoundary 布局边界

在开发中一般很不直接使用 RelayoutBoundary,我们可以使用三个条件来触发 RelayoutBodudary 生效。

3.1 constraints.isTight

强约束,Widget 的 size 已经被确定,里面的子 Widget 做任何变化,size 都不会变。那么从该 Widget 开始里面的任意子 Wisget 做任意变化,都不会对外有影响,就会被添加 Relayout boundary(说添加不科学,因为实际上这种情况,它会把 size 指向自己,这样就不会再向上递归而引起父 Widget 的Layout了)。

3.2 parentUsesSize == false

实际上 parentUsesSize 与 sizedByParent 看起来很像,但含义有很大区别

parentUsesSize 表示父 Widget 是否要依赖子 Widget 的 size,如果是 false,子Widget 要重新布局的时候并不需要通知 parent,布局的边界就是自身了。

3.3 sizedByParent == true

可以理解为‌"尺寸由父级全权决定"‌的布局模式。当 Widget 设置该属性时,它的尺寸不依赖自身内容计算,而是完全服从父级分配的约束条件,就像学生按照老师指定的座位表入座,无需自己找位置。

父级主导‌:尺寸由父级约束直接确定,跳过 Widget 自身的布局计算逻辑。

非严格约束‌:虽非isTight(严格约束),但通过父级规则(如 Flex 布局的剩余空间分配)仍能明确尺寸。

性能优化‌:避免子 Widget 重复计算尺寸,提升布局效率。

RelayoutBoundary 的设立原则是:‌子节点尺寸变化不会影响父节点尺寸‌。

sizedByParent == true,由于子节点尺寸完全依赖父节点约束,其自身尺寸变化不会向上传递影响父节点,因此自然满足 RelayoutBoundary 的条件。

二. 渲染优化

1. 控制刷新范围

将频繁更新的 UI 部分拆分为独立 Widget,避免全局刷新。例如验证码倒计时组件:通过将倒计时状态移至子组件(状态下移),避免父组件因状态更新而重建,实现精准刷新。

class CountdownButton extends StatefulWidget {
@override
_CountdownButtonState createState() => _CountdownButtonState();
}
class _CountdownButtonState extends State<CountdownButton> {
int _seconds = 60;
void _startCountdown() {
Timer.periodic(Duration(seconds: 1), (timer) {
if (_seconds == 0) timer.cancel();
setState(() => _seconds--);
});
}
@override Widget build(BuildContext context) => Text('$_seconds秒');
}

相比在父组件中使用 setState,此实现仅刷新倒计时文本。

2. 避免无效重建‌

使用 const 构造函数声明静态 Widget:

const Text('静态文本'), //  编译期确定
Text('动态文本') // 每次重建

3. 隔离重绘区域

对复杂子组件使用 RepaintBoundary 隔离重绘区域。

RepaintBoundary 隔离动画

RepaintBoundary(
child: AnimatedContainer(...), // 独立重绘的动画组件
)

三. 动画优化

1. AnimatedBuilder 最佳实践

预构建静态子组件避免重复创建:

AnimatedBuilder(
animation: _animation,
child: const HeavyWidget(), // 预构建
builder: (_, child) => Transform.rotate(
angle: _animation.value,
child: child // 复用子组件
)
)

相比直接在 builder 内创建子组件,性能提升约 16%。

‌2. 使用 Tween 动画‌

优先使用轻量级动画类型:

AnimationController(
duration: const Duration(seconds: 1),
vsync: this,
)..repeat(reverse: true);
final Animation<double> _animation = Tween(begin: 0.0, end: 1.0).animate(_controller);

四. 列表优化

1. 长列表处理‌

使用 ListView.builder+itemExtent 提升滚动性能:

ListView.builder(
itemCount: 10000,
itemExtent: 56.0, // 固定高度避免动态计算
itemBuilder: (ctx, i) => ListTile(title: Text('Item $i'))
)

结合 AutomaticKeepAliveClientMixin 实现状态保持。

2. ‌图片懒加载

使用 cached_network_image 优化网络图片:

CachedNetworkImage(
imageUrl: 'https://example.com/image.jpg',
placeholder: (_, __) => CircularProgressIndicator(),
errorWidget: (_, __, ___) => Icon(Icons.error),
)

五、状态管理优化

1. 精准更新‌

使用 Provider 实现局部刷新:

Selector<Model, String>(
selector: (_, model) => model.title,
builder: (_, title, __) => Text(title) // 仅title变化时重建
)

相比 Consumer 减少不必要的重建。

2. 避免 build 中创建对象

//  错误:每次build新建Logger
Widget build() {
final logger = Logger();
return ...
} // 正确:提前初始化
static const _logger = Logger();
Widget build() => ...

六. 工具与调试

1. 性能分析工具‌

  • 使用 DevTools 的 Performance 视图检测超时帧(红色标记)。
  • 开启 Repaint Rainbow 检查过度重绘的 Widget。

2. ‌构建模式‌

始终在 profile 模式下测试性能:

flutter run --profile

调试模式会引入额外性能开销。

通过以上六大方向的优化组合,可使 Flutter 应用达到 60FPS 的流畅体验。实际开发中建议结合 DevTools 持续监控性能指标。

Flutter UI 性能优化实践的更多相关文章

  1. 直播推流端弱网优化策略 | 直播 SDK 性能优化实践

    弱网优化的场景 网络直播行业经过一年多的快速发展,衍生出了各种各样的玩法.最早的网络直播是主播坐在 PC 前,安装好专业的直播设备(如摄像头和麦克风),然后才能开始直播.后来随着手机性能的提升和直播技 ...

  2. 手游录屏直播技术详解 | 直播 SDK 性能优化实践

    在上期<直播推流端弱网优化策略 >中,我们介绍了直播推流端是如何优化的.本期,将介绍手游直播中录屏的实现方式. 直播经过一年左右的快速发展,衍生出越来越丰富的业务形式,也覆盖越来越广的应用 ...

  3. Android UI性能优化详解

    设计师,开发人员,需求研究和测试都会影响到一个app最后的UI展示,所有人都很乐于去建议app应该怎么去展示UI.UI也是app和用户打交道的部分,直接对用户形成品牌意识,需要仔细的设计.无论你的ap ...

  4. 转:携程App的网络性能优化实践

    http://kb.cnblogs.com/page/519824/ 携程App的网络性能优化实践 受益匪浅的一篇文章,让我知道网络交互并不是简单的传输和接受数据.真正的难点在于后面的性能优化 下面对 ...

  5. Lazy<T>在Entity Framework中的性能优化实践

    Lazy<T>在Entity Framework中的性能优化实践(附源码) 2013-10-27 18:12 by JustRun, 328 阅读, 4 评论, 收藏, 编辑 在使用EF的 ...

  6. Redis各种数据结构性能数据对比和性能优化实践

    很对不起大家,又是一篇乱序的文章,但是满满的干货,来源于实践,相信大家会有所收获.里面穿插一些感悟和生活故事,可以忽略不看.不过听大家普遍的反馈说这是其中最喜欢看的部分,好吧,就当学习之后轻松一下. ...

  7. Unity UI性能优化技巧

    本文将介绍一些提升Unity UI性能的技巧.更多优化技巧,可以观看Unity工程师Ian Dundore在Unite Europe 2017的演讲<使用Unity性能提升技巧>. 1.划 ...

  8. Tree-Shaking性能优化实践 - 原理篇

    Tree-Shaking性能优化实践 - 原理篇   一. 什么是Tree-shaking 先来看一下Tree-shaking原始的本意 上图形象的解释了Tree-shaking 的本意,本文所说的前 ...

  9. Hadoop YARN:调度性能优化实践(转)

    https://tech.meituan.com/2019/08/01/hadoop-yarn-scheduling-performance-optimization-practice.html 文章 ...

  10. 让Elasticsearch飞起来!——性能优化实践干货

    原文:让Elasticsearch飞起来!--性能优化实践干货 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog ...

随机推荐

  1. Web前端入门第 77 问:JavaScript 由程序触发绑定事件的几种方式

    开发中经常会遇这样的需求:点击 A 元素的时候,需要触发 B 元素的事件,比如:点击一个 div 元素,然后触发 input:file 的 click 事件,用来选择文件上传. click 方法 以上 ...

  2. FRP 各种操作系统的接口

    简介 类似于TeamViewer之类,而更好的用内网穿透的东西. 参考链接 https://zhuanlan.zhihu.com/p/79793246

  3. java bitset and C++ bitset

    简介 素数运算C++和java速度比较 C++ code /* * @Author: your name * @Date: 2020-10-28 09:06:43 * @LastEditTime: 2 ...

  4. REST和GraphQL究竟谁才是API设计的终极赢家?

    扫描二维码 关注或者微信搜一搜:编程智域 前端至全栈交流与成长 发现1000+提升效率与开发的AI工具和实用程序:https://tools.cmdragon.cn/ 一.核心概念与技术对比 (一)R ...

  5. ETL工具观察:ETLCloud与MDM是什么关系?

    一.什么是ETLCloud ETLCloud数据中台是一款高时效的数据集成平台,专注于解决大数据量和高合规要求环境下的数据集成需求. 工具特点 1.离线与实时集成:支持离线数据集成(ETL.ELT)和 ...

  6. css样式入门学习

    css样式入门学习 一.css是什么 css 又叫层叠样式表 Cascading style sheets CSS层疊样式表是一门标记语言,并不是编程语言,因此不可以自定义变量,不可以引用等,换句话说 ...

  7. mysql中date_format函数格式化日期,如何精确到毫秒?

    直接看官网文档 : https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_date-format ...

  8. Behavior designer 行为树插件 笔记

    插件下载:https://files-cdn.cnblogs.com/files/sanyejun/BehaviorDesigner1.6.4.7z 参考资料:https://blog.csdn.ne ...

  9. 将AtomicInteger对象作为方法的局部变量, 传递给其他线程, 读写操作是否是线程安全的?

    目录 将AtomicInteger对象作为方法的局部变量, 传递给其他线程, 读写操作是否是线程安全的? 场景 代码 运行结果 总结 将AtomicInteger对象作为方法的局部变量, 传递给其他线 ...

  10. 单片机+WiFi模块和主流物联网平台实现MQTT协议通信视频教程

    单片机+WiFi模块和主流物联网平台实现MQTT协议通信视频教程 1.单片机+WiFi模块和阿里云物联网平台实现MQTT协议通信视频教程单片机+WiFi模块和阿里云物联网平台实现MQTT协议通信,阿里 ...