npx skills add https://github.com/flutter/skills --skill flutter-performance通过识别卡顿、过度重建和昂贵的渲染操作,分析和优化 Flutter 应用程序性能。实施 UI 渲染、状态管理和布局约束的最佳实践。利用 Flutter DevTools、Chrome DevTools(用于 Web)和集成测试来生成可操作的性能指标,确保帧在严格的 16ms 预算内渲染。
使用以下决策树评估目标应用程序以确定优化路径:
traceAction 和 TimelineSummary 实现集成测试。debugProfileBuildsEnabled 并使用 Chrome DevTools 性能面板。--profile 模式运行应用程序并启动 Flutter DevTools。广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
build()setState()constStringBuffersaveLayer()、Opacity、Clip 和 ImageFilter 的使用。使用 RepaintBoundary 预缓存复杂图像。test_driver/perf_driver.dart (不可变操作):
import 'package:flutter_driver/flutter_driver.dart' as driver;
import 'package:integration_test/integration_test_driver.dart';
Future<void> main() {
return integrationDriver(
responseDataCallback: (data) async {
if (data != null) {
final timeline = driver.Timeline.fromJson(
data['scrolling_timeline'] as Map<String, dynamic>,
);
final summary = driver.TimelineSummary.summarize(timeline);
await summary.writeTimelineToFile(
'scrolling_timeline',
pretty: true,
includeSummary: true,
);
}
},
);
}
integration_test/scrolling_test.dart :
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:your_package/main.dart';
void main() {
final binding = IntegrationTestWidgetsFlutterBinding.ensureInitialized();
testWidgets('Performance profiling test', (tester) async {
await tester.pumpWidget(const MyApp());
final listFinder = find.byType(Scrollable);
final itemFinder = find.byKey(const ValueKey('target_item'));
await binding.traceAction(() async {
await tester.scrollUntilVisible(
itemFinder,
500.0,
scrollable: listFinder,
);
}, reportKey: 'scrolling_timeline');
});
}
使用以下命令运行测试:flutter drive --driver=test_driver/perf_driver.dart --target=integration_test/scrolling_test.dart --profile --no-dds
优化 UI 线程(构建成本) 如果 UI 线程每帧超过 8ms,请重构 widget 树:
setState 调用移动到 widget 树的低层。const: 应用 const 构造函数以短路重建遍历。StringBuffer 替换 + 操作符。// 错误:重建整个 widget 树
setState(() { _counter++; });
// 正确:封装的状态
class CounterWidget extends StatefulWidget { ... }
// 在 CounterWidget 内部:
setState(() { _counter++; });
// 正确:高效的字符串构建
final buffer = StringBuffer();
for (int i = 0; i < 1000; i++) {
buffer.write('Item $i');
}
final result = buffer.toString();
3. 优化 Raster 线程(渲染成本) 如果 Raster 线程每帧超过 8ms,请消除昂贵的绘制操作:
* 尽可能用半透明颜色替换 `Opacity` widget。
* 在动画中用 `AnimatedOpacity` 或 `FadeInImage` 替换 `Opacity`。
* 避免使用 `Clip.antiAliasWithSaveLayer`。在容器上使用 `borderRadius` 属性,而不是显式的裁剪 widget。
// 错误:昂贵的 Opacity widget
Opacity(
opacity: 0.5,
child: Container(color: Colors.red),
)
// 正确:半透明颜色
Container(color: Colors.red.withOpacity(0.5))
4. 修复布局和固有传递 识别并消除由固有操作引起的过度布局传递(例如,在布局之前询问所有子项的大小)。
* 对长列表使用惰性构建器(`ListView.builder`、`GridView.builder`)。
* 除非绝对必要,否则避免在可滚动组件上使用 `ShrinkWrap: true`。
5. 处理框架破坏性变更(验证并修复) 确保应用程序遵守最近关于 LayoutBuilder 和 OverlayEntry 的 Flutter 优化变更。这些 widget 不再隐式重建。
* **验证:** 检查 `LayoutBuilder` 或 `OverlayEntry` UI 是否未能更新。
* **修复:** 将触发更新的状态修改包装在显式的 `setState` 中。
// 修复:针对 Overlay/Route 变更的显式 setState
final newLabel = await Navigator.pushNamed(context, '/bar');
setState(() {
buttonLabel = newLabel;
});
6. Web 特定性能分析 如果为 Web 进行性能分析,请在 runApp() 之前将这些标志添加到 main() 中,以将时间线事件注入 Chrome DevTools:
import 'package:flutter/widgets.dart';
import 'package:flutter/rendering.dart';
void main() {
debugProfileBuildsEnabled = true;
debugProfileBuildsEnabledUserWidgets = true;
debugProfileLayoutsEnabled = true;
debugProfilePaintsEnabled = true;
runApp(const MyApp());
}
停止并询问用户: "您是否捕获了 Chrome DevTools 性能分析?如果您需要具体的重构建议,请分享时间线事件瓶颈。"
--profile 模式。Widget 对象上重写 operator ==。这会导致 O(N²) 行为并降低性能。请依赖 const 缓存。AnimatedBuilder。将静态部分构建一次,并将其作为 child 参数传递。List 的构造函数(例如 Column、ListView),如果大多数子项在屏幕外。始终使用 .builder 构造函数进行惰性加载。saveLayer(),除非绝对必要(例如,具有透明度的动态重叠形状)。预计算并缓存静态重叠形状。每周安装量
1.2K
代码仓库
GitHub 星标数
792
首次出现
2026年3月4日
安全审计
安装于
codex1.1K
github-copilot1.1K
opencode1.1K
cursor1.1K
gemini-cli1.1K
kimi-cli1.1K
Analyzes and optimizes Flutter application performance by identifying jank, excessive rebuilds, and expensive rendering operations. Implements best practices for UI rendering, state management, and layout constraints. Utilizes Flutter DevTools, Chrome DevTools (for web), and integration tests to generate actionable performance metrics, ensuring frames render within the strict 16ms budget.
Evaluate the target application using the following decision tree to determine the optimization path:
traceAction and TimelineSummary.debugProfileBuildsEnabled and use Chrome DevTools Performance panel.--profile mode and launch Flutter DevTools.build() methods, localize setState(), use const constructors, and replace string concatenation with StringBuffer.saveLayer(), Opacity, Clip, and ImageFilter usage. Pre-cache complex images using RepaintBoundary.test_driver/perf_driver.dart (Immutable operation):
import 'package:flutter_driver/flutter_driver.dart' as driver;
import 'package:integration_test/integration_test_driver.dart';
Future<void> main() {
return integrationDriver(
responseDataCallback: (data) async {
if (data != null) {
final timeline = driver.Timeline.fromJson(
data['scrolling_timeline'] as Map<String, dynamic>,
);
final summary = driver.TimelineSummary.summarize(timeline);
await summary.writeTimelineToFile(
'scrolling_timeline',
pretty: true,
includeSummary: true,
);
}
},
);
}
integration_test/scrolling_test.dart :
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:your_package/main.dart';
void main() {
final binding = IntegrationTestWidgetsFlutterBinding.ensureInitialized();
testWidgets('Performance profiling test', (tester) async {
await tester.pumpWidget(const MyApp());
final listFinder = find.byType(Scrollable);
final itemFinder = find.byKey(const ValueKey('target_item'));
await binding.traceAction(() async {
await tester.scrollUntilVisible(
itemFinder,
500.0,
scrollable: listFinder,
);
}, reportKey: 'scrolling_timeline');
});
}
Run the test using: flutter drive --driver=test_driver/perf_driver.dart --target=integration_test/scrolling_test.dart --profile --no-dds
Optimize UI Thread (Build Costs) If the UI thread exceeds 8ms per frame, refactor the widget tree:
setState calls as low in the widget tree as possible.const: Apply const constructors to short-circuit rebuild traversals.+ operators in loops with StringBuffer.// BAD: Rebuilds entire widget tree
setState(() { _counter++; });
// GOOD: Encapsulated state
class CounterWidget extends StatefulWidget { ... }
// Inside CounterWidget:
setState(() { _counter++; });
// GOOD: Efficient string building
final buffer = StringBuffer();
for (int i = 0; i < 1000; i++) {
buffer.write('Item $i');
}
final result = buffer.toString();
3. Optimize Raster Thread (Rendering Costs) If the Raster thread exceeds 8ms per frame, eliminate expensive painting operations:
* Replace `Opacity` widgets with semitransparent colors where possible.
* Replace `Opacity` in animations with `AnimatedOpacity` or `FadeInImage`.
* Avoid `Clip.antiAliasWithSaveLayer`. Use `borderRadius` properties on containers instead of explicit clipping widgets.
// BAD: Expensive Opacity widget
Opacity(
opacity: 0.5,
child: Container(color: Colors.red),
)
// GOOD: Semitransparent color
Container(color: Colors.red.withOpacity(0.5))
4. Fix Layout and Intrinsic Passes Identify and remove excessive layout passes caused by intrinsic operations (e.g., asking all children for their size before laying them out).
* Use lazy builders (`ListView.builder`, `GridView.builder`) for long lists.
* Avoid `ShrinkWrap: true` on scrollables unless absolutely necessary.
5. Handle Framework Breaking Changes (Validate-and-Fix) Ensure the application complies with recent Flutter optimization changes regarding LayoutBuilder and OverlayEntry. These widgets no longer rebuild implicitly.
* **Validate:** Check if `LayoutBuilder` or `OverlayEntry` UI fails to update.
* **Fix:** Wrap the state modification triggering the update in an explicit `setState`.
// FIX: Explicit setState for Overlay/Route changes
final newLabel = await Navigator.pushNamed(context, '/bar');
setState(() {
buttonLabel = newLabel;
});
6. Web-Specific Profiling If profiling for Web, inject timeline events into Chrome DevTools by adding these flags to main() before runApp():
import 'package:flutter/widgets.dart';
import 'package:flutter/rendering.dart';
void main() {
debugProfileBuildsEnabled = true;
debugProfileBuildsEnabledUserWidgets = true;
debugProfileLayoutsEnabled = true;
debugProfilePaintsEnabled = true;
runApp(const MyApp());
}
STOP AND ASK THE USER: "Have you captured the Chrome DevTools performance profile? Please share the timeline event bottlenecks if you need specific refactoring."
--profile mode on a physical device.operator == on Widget objects. It results in O(N²) behavior and degrades performance. Rely on const caching instead.AnimatedBuilder that does not depend on the animation. Build the static part once and pass it as the child parameter.List of children (e.g., Column, ListView) if most children are off-screen. Always use constructors for lazy loading.Weekly Installs
1.2K
Repository
GitHub Stars
792
First Seen
Mar 4, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
codex1.1K
github-copilot1.1K
opencode1.1K
cursor1.1K
gemini-cli1.1K
kimi-cli1.1K
React 组合模式指南:Vercel 组件架构最佳实践,提升代码可维护性
102,200 周安装
.buildersaveLayer() unless absolutely necessary (e.g., dynamic overlapping shapes with transparency). Precalculate and cache static overlapping shapes.