HarmonyOS 鸿蒙Next 如何减少页面布局的嵌套层数以优化性能?
HarmonyOS 鸿蒙Next 如何减少页面布局的嵌套层数以优化性能?
实际应用场景:复杂的页面布局可能导致渲染性能下降,通过扁平化布局优化性能。
背景介绍
应用开发中的用户界面(UI)布局是用户与应用程序交互的关键部分。使用不同类型的布局可以将页面排布的更加美观,但是不合理的使用,虽然能在界面显示上达到相同效果,但是过渡的布局计算,界面嵌套带来了渲染和计算的大量开销,造成性能的衰退,本文重点介绍了几种常见的布局功能和适用场景,同时列举了多层嵌套布局场景造成的性能问题,并探索通过布局扁平化手段进行性能提升。
常用布局列举
如果你经常使用ArkUI编程,你应该已经能非常熟练的使用Stack、Column、Row、Flex等组件编写UI页面了。
- 使用Stack构建层叠布局
- 使用Row、Column构建线性布局
- 使用Flex构建弹性布局
上述布局都属于线性布局,顾名思义,在线性布局中排布的组件是按照特定的方向线性放置,如横向/纵向/Z序方向。
除上述布局类型外,还有一些高级布局能力,List、Grid、GridRow、RelativeContainer和自定义布局。
每种布局是为了解决一种或多种布局场景。
- List既具备线性布局的特点,同时支持懒加载和滑动的能力
- Grid提供了宫格布局的能力,同时也支持懒加载和滑动能力
- GridRow是推荐使用的栅格布局,栅格布局具有良好的多分辨率自适应效果和弹性伸缩的能力
- RelativeContainer是一种相对布局,通过描述各个内容组件间相互关系来指导内容元素的布局过程,可从横纵两个方面进行布局描述,是一种二维布局算法。
- 自定义布局,框架还提供了一种自定义布局机制,当布局场景非常复杂或不宜抽象时,可采用该种布局能力,自行实现布局效果,如实现圆形布局或延曲线排布等效果
布局使用过程中出现的性能问题
下面我们通过一个示例,展示布局对性能的影响有哪些。
案例介绍
界面效果
例如我们开发一个聊天软件,每个聊天项是一个自定义组件。直观上看,我们构建一个聊天项会先选用横向布局(Row
)作为根布局,分别排布图标,聊天内容和时间。在聊天内容部分选用纵向布局(Column
)排布用户名和聊天内容文本
使用扁平化布局减少嵌套层数
对于一些页面,错误的布局使用可能会导致组件树和嵌套层数过多。在创建和布局阶段产生较大的性能开销。
嵌套层数过多的一个案例
当应用使用线性布局组件实现以上的UI时,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
[@Component](/user/Component) struct MyComponent { build() { Row() { Column() { Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) { //SMS message type. 0: common; 1: notification Text('张') .fontSize('20.0vp') .fontWeight(FontWeight.Bold) .fontColor(Color.White) .height("40vp") .width("40vp") .textAlign(TextAlign.Center) .clip(new Circle({ width: "40vp", height: "40vp" })) .backgroundColor(Color.Green) } .width("40vp") .height("40vp") }.height("100%").justifyContent(FlexAlign.Center) //body Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.Start }) { Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.Center }) { Flex({ direction: FlexDirection.Row, justifyContent: FlexAlign.SpaceBetween, alignItems: ItemAlign.Center }) { //Phone number or first name Text('张三') .fontSize('16.0fp') .textOverflow({ overflow: TextOverflow.Ellipsis }) .fontColor('#ff182431') .maxLines(1) .fontWeight(FontWeight.Medium) //Date Time Text('2分钟前') .fontColor('#66182431') .fontSize("12fp") .maxLines(1) .flexShrink(0) }.width("100%").height(22) Row() { Text() { //Content Abbreviations for Latest News Span('Hello World'.replace(/[\r\n]/g, " ")) .fontSize("14fp") .fontColor('#66182431') } .maxLines(1) .textOverflow({ overflow: TextOverflow.Ellipsis }) } .alignSelf(ItemAlign.Start) .alignItems(VerticalAlign.Top) .width("100%") .height(19) .margin({ top: "2vp" }) }.width("100%") .height("100%") } .layoutWeight(1) .height("100%") .padding({ left: "12vp" }) } .alignItems(VerticalAlign.Top) .width("100%") .height("100%") } }
使用deveco Testing 中的UIView工具,可以清晰的看到组件树状结构:
为了将4个元素放到合适的位置,开发者使用了多达11个组件,树深度为5。
分析元素之间的布局关系:
可以得到一个明确的相对布局位置关系,该场景可以使用相对布局的形式来优化:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
[@Entry](/user/Entry) [@Component](/user/Component) struct MyComponent { build() { Row() { RelativeContainer() { Text('张') .fontSize('20.0vp') .fontWeight(FontWeight.Bold) .fontColor(Color.White) .height("40vp") .width("40vp") .textAlign(TextAlign.Center) .clip(new Circle({ width: "40vp", height: "40vp" })) .backgroundColor(Color.Green) .alignRules({ center: {anchor: "__container__", align: VerticalAlign.Center}, left: {anchor: "__container__", align: HorizontalAlign.Start} }) .id("head") Text('张三') .fontSize('16.0fp') .textOverflow({ overflow: TextOverflow.Ellipsis }) .fontColor('#ff182431') .maxLines(1) .fontWeight(FontWeight.Medium) .padding({ left: "12vp" }) .height(22) .alignRules({ top: {anchor: "head", align: VerticalAlign.Top}, left: {anchor: "head", align: HorizontalAlign.End} }) .id("name") Text('2分钟前') .fontColor('#66182431') .fontSize("12fp") .maxLines(1) .height(22) .alignRules({ top: {anchor: "head", align: VerticalAlign.Top}, right: {anchor: "__container__", align: HorizontalAlign.End} }) .id("time") Text() { //Content Abbreviations for Latest News Span('Hello World'.replace(/[\r\n]/g, " ")) .fontSize("14fp") .fontColor('#66182431') } .maxLines(1) .textOverflow({ overflow: TextOverflow.Ellipsis }) .width("100%") .height(19) .margin({ top: "2vp" }) .padding({ left: "12vp" }) .alignRules({ top: {anchor: "name", align: VerticalAlign.Bottom}, left: {anchor: "head", align: HorizontalAlign.End} }) .id("content") } .width('100%').height('100%') .border({width:1, color: "#6699FF"}) } .height('100%') } }
优化前后对比:
组件总数 | 嵌套层数 | |
---|---|---|
树形布局 | 11 | 5 |
相对布局 | 5 | 2 |
扁平化的布局理念
从上述案例中可以看到,选用正确的布局逻辑概念设计更清晰,同时去除了中间嵌套的很多不参与绘制的布局组件,达到优化性能减少内存占用的目的。我们称这种将一棵深度很高的UI树,改造为将内容排布到同一个节点下的思路,为扁平化布局。如下图所示,采用扁平化布局去除了中间冗余的两层布局节点。
使用扁平化布局推荐使用下述布局方案
- RelativeContainer 请查看ArkUI相对布局组件RelativeContainer的介绍。
- 绝对定位 请查看ArkUI定位能力位置设置的介绍。
- 自定义布局 请查看ArkUI自定义布局自定义组件的生命周期的介绍
- Grid 请查看ArkUI Grid组件使用指导Grid组件的介绍
更多关于HarmonyOS 鸿蒙Next 如何减少页面布局的嵌套层数以优化性能?的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
在HarmonyOS鸿蒙Next中,减少页面布局的嵌套层数以优化性能,可以采取以下方法:
- 使用扁平化布局:在进行页面布局开发时,尽量使用相对布局、绝对定位、自定义布局、Grid、GridRow等扁平化布局方式,避免布局嵌套过深。例如,可以使用Column/Row替代Flex来构建线性布局,以减少布局层级。
- 删除冗余嵌套:去除build最外层的无用容器嵌套、无用的Stack或Column嵌套等。检查布局结构,确保每个容器都有其必要性,去除那些仅作为包裹其他容器的冗余容器。
- 优化组件使用:在开发过程中,避免在组件内部再嵌套相同类型的布局容器。例如,如果父容器已经是Row类型,子容器应避免再次使用Row,除非有特定的布局需求。
通过上述方法,可以有效减少页面布局的嵌套层数,从而降低系统绘制布局组件的开销,提升页面渲染性能。如果问题依旧没法解决请联系官网客服,官网地址是:https://www.itying.com/category-93-b0.html。