HarmonyOS(58) 性能优化之合理使用布局组件
合理使用布局
1、减少UI组件层级嵌套
布局阶段是采用递归遍历所有节点的方式进行组件位置和大小的计算, 如果嵌套层级过深,将带来了更多的中间节点,将导致更多的计算过程,造成性能劣化。
反例:
Row() {
Row() {
Text('Inner Text')
}
...
}
上述代码,由于其中Row容器父子布局方向相同,所以可以去掉Image和Text外层的Row来减少层级,如果视图更加复杂,布局在渲染时,会产生没有必要的计算。所以我们可以进行如下改造:
Row() {
Image()
Text()
Image()
}
针对减少总节点,减少不必要的嵌套,主要有两个方向展开:
- 移除冗余的节点。
- 使用扁平化布局减少节点数
1.1 减少自定义组件产生多余节点
而给自定义组件添加属性,会在自定义组件外部会创建一个“Common”类型的节点,如下图所示。为了避免这类“Common”节点的创建,可以将自定义组件的属性移至内部,或者动态设置自定义组件的属性。减少自定义组件产生多余节点,可以使总节点数量降低,从而提升性能。所以当需要给自定义组件添加属性时,一般少量属性的场景下,可以将这些属性移至自定义组件内部
反例:
export struct Example {
build() {
Column() {
// 自定义组件
FlowListStruct({
// 自定义组件传递参数
// ...
}).backgroundColor('#FFFFFF')
}
.width('100%')
.height('100%')
}
}
正例:
export struct FlowListStruct {
build(){
Column(){
// ...
}
.backgroundColor('#FFFFFF')
}
}
2、使用扁平化布局减少节点数
扁平化布局是一种让页面结构变浅变宽的方式,主要目的是用来减少UI嵌套深度,减少布局节点,
常见的扁平化布局方案主要包括:
- RelativeContainer通过相对布局实现扁平化。
RelativeContainer - 绝对定位 通过锚点定位实现扁平化。
- Grid 通过二维布局实现扁平化。
3、指定组件的宽高
对于组件的宽高不需要自适应的情况下,建议在UI描述时给定组件的宽高数值,当其组件外部的容器尺寸发生变化时,例如拖拽缩放等场景下,如果组件本身的宽高是固定的,理论上来讲,该组件在布局阶段不会参与Measure阶段,其节点中保存了对应的大小信息,如果组件内容较多时,由于避免了其中组件整体的测算过程,性能会带来较大的提升。
开发中对于能够在初期给定宽高的组件,在进行UI描述时尽量给定宽高数值,能够减少由于容器尺寸变化造成的重新测算过程的性能消耗。
4、合理控制组件显示与隐藏
控制元素显示与隐藏是一种常见的场景,使用Visibility.None、if条件判断等都能够实现该效果。其中if条件判断控制的是组件的创建、布局阶段,visibility属性控制的是元素在布局阶段是否参与布局渲染。
- 如果只有初始的一次渲染或者交互次数很少的情况下,建议使用if条件判断来控制元素的显示与隐藏效果,对于内存有较大提升。用if条件判断切换显示时,组件会因为条件改变而判断是否参与创建、布局过程,切换过程会出现较大的Measure的性能消耗,原因是创建了新的组件,重新进行了Measure和Layout的过程。
- 如果会频繁响应显示与隐藏的交互效果,建议使用切换Visibility.None和Visibility.Visible来控制元素显示与隐藏,提高性能。使用visibility的情况下,无论是否隐藏,组件在初次已经创建完成,并一直都存在组件树上,不会出现组件重新创建的过程,并且在Measure和Layout阶段的性能消耗比使用if/else的方式性能小很多,原因是组件的计算在首帧时已经计算过,不需要重复计算。
综上所述,在控制组件显示与隐藏时,建议遵循以下原则来选择使用控制方式:
- 在对性能要求较高,并且会频繁切换元素的显示与隐藏的情况下,应该避免使用if条件判断,而改为通过visibility的属性控制,这样在切换Visibility.None和Visibility.Visible时,可以省去组件创建的时间,直接进入渲染过程。
- 如果组件的创建非常消耗资源,且不会立即使用,也并非频繁切换交互的情况下,只在特定条件下才会出现时,可以通过if/else来进行内容的显示与隐藏控制,来达到懒加载的效果。
5、选择合适的布局组件
在布局深度和节点数相同的情况下:
- 使用基础组件如Column和Row容器的性能明显高于其他布局。
- Flex的性能明显低于Column和Row容器,这是由于Flex本身带来的二次布局的影响。
- Grid/GridItem布局、相对布局RelativeContainer的性能消耗高于基础组件Column、Row、Stack等容器。
在使用布局时尽量遵循以下原则:
- 在相同嵌套层级的情况下,如果多种布局方式可以实现相同布局效果,优选低耗时的布局,如使用Column、Row替代Flex实现相同的单行布局。
- 在能够通过其他布局大幅优化节点数的情况下,可以使用高级组件替代,如使用RelativeContainer替代Row、Column实现扁平化布局,此时其收益大于布局组件本身的性能差距。
- 仅在必要的场景下使用高耗时的布局组件,如使用Flex实现折行布局、使用Grid实现二维网格布局等。
6、Scroll嵌套List场景下,给定List组件宽高
在使用Scroll容器组件嵌套List组件加载长列表时,若不指定List的宽高尺寸,则默认全部加载。Scroll嵌套List时:
- List没有设置宽高时,List的所有子组件ListItem都会参与布局。
- List设置宽高,只有布局区域内的ListItem子组件会参与布局。
- List使用ForEach加载子组件时,无论是否设置List的宽高,都会加载所有子组件。
- List使用LazyForEach加载子组件时,没有设置List的宽高,会加载所有子组件,设置了List的宽高,会加载List显示区域内的子组
7、参考资料
更多推荐



所有评论(0)