Android应用篇 - UI 层级、过度绘制分析
过度绘制就是在同一个区域中叠加了多个控件,也就是说一个像素点上会出现多个像素的叠加,实际上呈现在我们眼前的只是最上面的一个,往往造成这种现象的原因是产品或者视觉过多繁琐的建议和交互,或者是开发人员自己不注意造成的。
目录:
- 如何分析过度绘制
- 如何解决过度绘制
1. 如何分析过度绘制
通过打开开发者选项中的"显示 GPU 过度绘制" (设置/更多设置/开发者选项/调试 GPU 过渡绘制 / 显示过渡绘制区域)来进行测试。
每个手机可能不一样,但是一定是有"调试 GPU 过渡绘制"选项 ,目前只有 Android 4.2 及以上的版本才具备此功能。
- 1.1 颜色标识
从好到差分别是:蓝 - 绿 - 淡红 - 红。
- 蓝色 1x 过度绘制。
- 绿色 2x 过度绘制。
- 淡红色 3x 过度绘制。
- 红色超过 4x 过度绘制。
- 1.2 验收标准
验收标准如下:
- 控制过度绘制为 2x。
- 不允许存在 4x 过度绘制。
- 不允许存在面积超过屏幕 1/4 区域的 3x 过度绘制 (淡红色区域)。
- 1.3 例子
这个页面就是超过了屏幕 1/4 的 3x 过度绘制。
2. 如何解决过度绘制
- 2.1 减少多余的 background
这个最重要,基本上都是因为这个原因造成的,解决好背景基本上就等于解决了大多数。
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:skin="http://schemas.android.com/android/skin"
android:background="@color/common_content_bg_color"
android:layout_height="match_parent"
android:layout_width="match_parent"
skin:enable="true">
<ai.ctxc.ui.widget.TopBar
android:id="@+id/top_bar"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:background="@color/common_content_bg_color" />
</RelativeLayout>
明显有同样的背景色重叠区域。
- 2.2 使用 style 或者 include 复用布局
这个主要是减少重复 xml 代码用的,方便维护。同时 include 可以配合 <merge> 标签使用,减少层级。
- 2.3 使用 ViewStub
ViewStub 需要时再加载布局。
- 2.4 使用 sdk 提供的工具 Hierarchy Viewer 进行层级分析
主要目的是减少层级。
- 2.5 this.getWindow().setBackgroundDrawable(null)
设置背景,这个要谨慎使用,在低端机上的使用可能会造成闪屏的情况。视图有背景,每个窗口也是有背景的。每个 Activity 是一个窗口,每个 Activity 都有不同得背景。界面的绘画顺序如下:窗口 - 跟视图 - 子视图。当我们的跟视图已经覆盖了整个窗口的时候 ,程序还是会画一个透明的窗口的背景,而这个背景用户是看不到的。我们就需要想办法让程序在这样的情况下去掉窗口背景,节约画窗口背景的时间提高效率。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 删除窗口背景
getWindow().setBackgroundDrawable(null);
}
或者这样:
<resources>
<style name="NoBackgroundTheme" parent="android:Theme">
<item name="android:windowBackground">@null</item>
</style>
</resources>
- 2.6 clipRect()
可以通过 canvas.clipRect() 来帮助系统识别那些可见的区域。这个方法可以指定一块矩形区域,只有在这个区域内才会被绘制,其他的区域会被忽视。这个 API 可以很好的帮助那些有多组重叠组件的自定义 View 来控制显示的区域。同时 clipRect 方法还可以帮助节约 CPU 与 GPU 资源,在 clipRect 区域之外的绘制指令都不会被执行,那些部分内容在矩形区域内的组件,仍然会得到绘制。
使用主要是传入两个 Rect 的坐标,然后设置不同的参数来实现最终绘制的区域,教程如下:Android画布剪裁函数clipRect详解