在您的应用中避免发生过度绘制。
应用中的“过度绘制”是指由于用户界面元素重叠而导致图形处理单元 (GPU) 多次渲染同一个像素的情况。当您的应用界面具有重叠图层且具有相似z顺序(渲染优先级)时,即使其他图层覆盖部分元素(遵循绘制者算法),GPU也会按堆叠顺序绘制每个图层。此进程重绘其他元素覆盖的像素而导致GPU资源浪费,从而在资源受限的设备上造成性能问题。
配置过度绘制检测
要配置应用过度绘制检测,请参阅配置应用启动选项。在项目启动选项中,输入SHOW_OVERDRAWN=true。然后,在Vega Studio中运行应用。
如何解释过度绘制结果
应用会使用颜色指示器显示过度绘制:
| 颜色 | 过度绘制级别 |
|---|---|
| 蓝色 | GPU过度绘制1次 |
| 绿色 | GPU过度绘制2次 |
| 粉色 | GPU过度绘制3次 |
| 红色 | GPU过度绘制4次及以上 |
如何减少过度绘制
确定应用中的过度绘制区域后,使用以下优化技术来最大限度地减少GPU工作负载并提高渲染性能:
将视图层次结构扁平化
更扁平的视图层次结构可以减少纯React应用的过度绘制,但是React Native的视图扁平化优化可能会扁平化某些视图,从而为您精简原生组件树。该算法会研究backgroundColor、margin、padding或opacity样式属性,以确定它是否可以将视图扁平化为父视图。
在Javascript中,您的组件树层次结构看起来是一样的,因为React Native原生地应用了这种优化。因此,使用诸如React Dev Tools的组件层次结构查看器之类的工具仍然会显示与JS代码相同的层次结构。从用户的角度来看,屏幕上没有明显的变化。通过减少原生视图层的数量,这种优化最大限度地减少了由于视图重叠而导致的GPU多次渲染像素的过度绘制,从而提高了渲染性能和用户界面交互的流畅度。
// React Native原生地扁平化了这段代码
import React from "react";
import { View, Text, StyleSheet } from "react-native";
export default function App() {
return (
<View style={styles.container}>
<View style={styles.cardOuter}>
<View style={styles.cardInner}>
<Text style={styles.cardText}>React Native视图扁平化示例</Text>
</View>
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: "center",
alignItems: "center",
backgroundColor: "#f4f4f4",
},
cardOuter: {
padding: 12,
borderRadius: 8,
},
cardInner: {
padding: 16,
borderRadius: 8,
},
cardText: {
fontSize: 16,
color: "#333",
},
});
此图显示了JavaScript视图层次结构与扁平化原生层次结构的比较情况。
避免透明度以减少GPU工作负载
透明和半透明视图会导致过度绘制,因为GPU在应用透明效果之前必须渲染所有背景层。但是,在某些情况下,预计会出现过度绘制的情况。例如:
- 使用与应用其余部分不同的背景颜色渲染侧栏菜单会出现过度绘制的情况
- 使用半透明层来实现您的用户界面/用户体验。
如果可行,您希望最大限度地减少应用的大量过度绘制部分。较小的区域,例如轮播中缩略图大小的卡片,可以稍微过度绘制。
最佳实践:
- 尽可能使用不透明的颜色代替透明之处。
- 避免过度使用
backgroundColor。 - 在根级别设置一个
backgroundColor,并尽可能避免使用per-View背景颜色。 - 避免堆叠平面颜色和/或半透明图层(例如:背景颜色灰色、背景颜色白色、不透明度、阴影)。
示例:
// 避免这种情况:
<View style={{ backgroundColor: 'rgba(255, 0, 0, 0.5)' }} />
// 首选纯色:
<View style={{ backgroundColor: 'red' }} />
在示例中,0.5是RGBA格式的alpha(不透明度)值。当透明元素重叠时,GPU会分别计算和渲染每个图层,从而导致额外的绘制操作和性能问题。透明度进一步增加了GPU的工作量,因为GPU必须将背景内容与前景内容混合在一起,从而增加了额外的绘制操作和性能问题。
优化图像。
未经优化的较大图像会迫使GPU渲染超过必要数量的像素,从而增加过度绘制。优化图像以减少渲染开销。
-
为您的用例选择合适的图像格式:
- JPEG: 照片和复杂图像
- PNG: 具有透明度的图像
- WebP: 比JPEG/PNG更好的压缩率
- SVG: 简单的图标和图形
- 使用适当的图像大小和分辨率图像来匹配显示尺寸。如果各种尺寸(缩略图、海报、全屏)的图像资产不可用,请探索尺寸调整。
-
针对不同的屏幕密度使用多种分辨率:
- my-image.png (1x) 用于标准分辨率
- my-image@2x.png用于2倍分辨率的设备
- my-image@3x.png用于3倍分辨率的设备
- 使用基于百分比的维度或resizeMode进行响应式设计。这样可以确保图像在不同的屏幕尺寸上适当地缩放。
-
避免使用
resizeMode: stretch,因为它会扭曲图像并导致渲染开销。使用“contain”或“cover”来保持宽高比。<Image style={{ width: 100, height: 100 }} source={{ uri: 'image.jpg' }} resizeMode="contain" /> - 将多个图标合并到一个文件中,以减少GPU的工作量。
减少屏幕外内容
渲染屏幕上不可见的内容会浪费GPU资源并导致不必要的过度绘制。虚拟化应用的组件树可以有效地管理内存中存在的组件,即使没有在屏幕上渲染它们,有助于减少屏幕外内容。
使用虚拟化组件:
虚拟化组件通过仅渲染屏幕上可见的项目来减少屏幕外内容。Vega支持多种高性能虚拟化列表选项,例如FlashList(v1和v2)、LegendList、Carousel和其他纯JS列表组件。为您的用例选择适当的虚拟化列表组件。
最佳实践:
- 为您的用例选择合适的虚拟化组件。
- 避免渲染较大的屏幕外内容区域。
- 对折叠下面的内容实现延迟加载。
- 移除或推迟隐藏用户界面元素的渲染。
访问应用性能最佳实践,了解实现详情。
使用变换属性优化动画
避免为height、width或margin等布局属性进行动画处理,因为这会触发开销高昂的重新计算并增加过度绘制。取而代之的是,对在GPU上运行且不影响布局的变换属性(仅提供英文版)(scale、rotate、translate)进行动画处理。使用useNativeDriver: true可确保动画在原生线程上运行:
// 而不是对布局属性进行动画处理:
<Animated.View style={{ height: animatedHeight }}>
...
</Animated.View>
// 改为对变换属性进行动画处理:
<Animated.View style={{ transform: [{ translateY: animatedTranslateY }] }}>
...
</Animated.View>
摘要
为避免应用中的过度绘制,首先启用过度绘制检测以了解问题。如果您无法修复无法衡量的内容,请重点关注:
- 优化图像和动画。
- 减少不必要的重新渲染。
- 移除不必要的包装器。
- 使用适当的组件,例如FlashList。
- 减少GPU工作量和返工。
相关主题
Last updated: 2025年12月22日

