16、鸿蒙/布局/相对布局 (RelativeContainer
概述
在应用的开发过程中,经常需要设计复杂界面,此时涉及到多个相同或不同组件之间的嵌套。如果布局组件嵌套深度过深,或者嵌套组件数过多,会带来额外的开销。如果在布局的方式上进行优化,就可以有效的提升性能,减少时间开销。
RelativeContainer为采用相对布局的容器,支持容器内部的子元素设置相对位置关系,适用于界面复杂场景的情况,对多个子组件进行对齐和排列。子元素支持指定兄弟元素作为锚点,也支持指定父容器作为锚点,基于锚点做相对位置布局。下图是一个RelativeContainer的概念图,图中的虚线表示位置的依赖关系。
RelativeContainer.png
基本概念
- 锚点:通过锚点设置当前元素基于哪个元素确定位置。
- 对齐方式:通过对齐方式,设置当前元素是基于锚点的上中下对齐,还是基于锚点的左中右对齐。
设置依赖关系
-
锚点设置
锚点设置是指设置子元素相对于父元素或兄弟元素的位置依赖关系。在水平方向上,可以设置left、middle、right的锚点。在竖直方向上,可以设置top、center、bottom的锚点。为了明确定义锚点,必须为RelativeContainer及其子元素设置ID,用于指定锚点信息。ID默认为“container”,其余子元素的ID通过id属性设置。未设置ID的子元素在RelativeContainer中不会显示。互相依赖,环形依赖时容器内子组件全部不绘制。同方向上两个以上位置设置锚点,但锚点位置逆序时此子组件大小为0,即不绘制。
-
RelativeContainer父组件为锚点,container代表父容器的ID。
RelativeContainer(){
//
Row(){}.backgroundColor(Color.Red).width(100).height(100)
.id('row1')
.alignRules({
// anchor 以谁为锚地点定位,__container__为容器
'top': { 'anchor': '__container__', 'align': VerticalAlign.Top },
'left': { 'anchor': '__container__', 'align': HorizontalAlign.Start }
})
//
Row(){}.backgroundColor(Color.Yellow).width(100).height(100)
.alignRules({
'top': { 'anchor': '__container__', 'align': VerticalAlign.Top },
'right': { 'anchor': '__container__', 'align': HorizontalAlign.End }
})
.id('row2')
Row(){}.backgroundColor(Color.Gray).width(100).height(100)
.alignRules({
// anchor 以谁为锚地点定位,row2为id为row2元素
'top': { 'anchor': 'row2', 'align': VerticalAlign.Center },
'right': { 'anchor': 'row2', 'align': HorizontalAlign.Start }
})
.id('row3')
}
- 以兄弟元素为锚点。
RelativeContainer(){
Row().backgroundColor(Color.Red).width(100).height(100).id('row1')
Row().backgroundColor(Color.Yellow).width(100).height(100).id('row2')
.alignRules({
'top': { 'anchor': 'row1', 'align': VerticalAlign.Bottom },
'right': { 'anchor': 'row1', 'align': HorizontalAlign.End }
})
}
- 子组件锚点可以任意选择,但需注意不要相互依赖。
RelativeContainer(){
Row().backgroundColor(Color.Red).width(100).height(100).id('row1')
.alignRules({
top: {anchor: "__container__", align: VerticalAlign.Top},
left: {anchor: "__container__", align: HorizontalAlign.Start}
})
Row().backgroundColor(Color.Yellow).width(100).height(100).id('row2')
.alignRules({
top: {anchor: "__container__", align: VerticalAlign.Top},
right: {anchor: "__container__", align: HorizontalAlign.End},
bottom: {anchor: "row1", align: VerticalAlign.Center},
})
Row().backgroundColor(Color.Gray).width(100).height(100).id('row3')
.alignRules({
top: {anchor: "row1", align: VerticalAlign.Bottom},
left: {anchor: "row1", align: HorizontalAlign.Start},
right: {anchor: "row2", align: HorizontalAlign.Start}
})
}
设置相对于锚点的对齐位置
设置了锚点之后,可以通过align设置相对于锚点的对齐位置。
在水平方向上,对齐位置可以设置为HorizontalAlign.Start、HorizontalAlign.Center、HorizontalAlign.End。
HorizontalAlign.png
在竖直方向上,对齐位置可以设置为VerticalAlign.Top、VerticalAlign.Center、VerticalAlign.Bottom。
VerticalAlign.png
子组件位置偏移
子组件经过相对位置对齐后,位置可能还不是目标位置,开发者可根据需要进行额外偏移设置offset。
RelativeContainer(){
Row().backgroundColor(Color.Red).width(100).height(100).id('row1')
.alignRules({
top: {anchor: "__container__", align: VerticalAlign.Top},
left: {anchor: "__container__", align: HorizontalAlign.Start}
})
//
Row().backgroundColor(Color.Yellow).width(100).height(100).id('row2')
.alignRules({
top: {anchor: "row1", align: VerticalAlign.Bottom},
left: {anchor: "row1", align: HorizontalAlign.Start}
})
.offset( // 通过offset设置位置偏移
{
x: -40,
y: 20
}
)
}
多种组件的对齐布局
Row、Column、Flex、Stack等多种布局组件,可按照RelativeContainer组件规则进行对其排布。
RelativeContainer(){
// flex
Row(){
Text('广告')
}.backgroundColor(Color.Red).height(100).width('100%').id('row1')
.alignRules({
top: {anchor: "__container__", align: VerticalAlign.Top},
left: {anchor: "__container__", align: HorizontalAlign.Start}
})
// flex
Flex(){
Text('新闻').flexGrow(1).height(30).backgroundColor(Color.Red).textAlign(TextAlign.Center)
Text('娱乐').flexGrow(1).height(30).backgroundColor(Color.Yellow).textAlign(TextAlign.Center)
Text('汽车').flexGrow(1).height(30).backgroundColor(Color.Gray).textAlign(TextAlign.Center)
Text('汽车').flexGrow(1).height(30).backgroundColor(Color.Gray).textAlign(TextAlign.Center)
}
.id('flex1')
.alignRules({
top: {anchor: "row1", align: VerticalAlign.Bottom},
left: {anchor: "row1", align: HorizontalAlign.Start}
}).offset({y: 10})
// column
Column(){
Row(){
Text('活动1').width('25%').height(100).backgroundColor(Color.Gray).textAlign(TextAlign.Center)
Text('活动2').width('25%').height(100).backgroundColor(Color.Green).textAlign(TextAlign.Center)
Text('活动2').width('25%').height(100).backgroundColor(Color.Gray).textAlign(TextAlign.Center)
Text('活动2').width('25%').height(100).backgroundColor(Color.Green).textAlign(TextAlign.Center)
}
}.alignRules({
top: {anchor: "flex1", align: VerticalAlign.Bottom},
left: {anchor: "flex1", align: HorizontalAlign.Start}
}).offset({y: 20})
//
Stack(){
Text('Top')
}.backgroundColor(Color.Blue).width(100).height(100)
.alignRules({
top: {anchor: "__container__", align: VerticalAlign.Center},
left: {anchor: "__container__", align: HorizontalAlign.Center}
})
}
多种布局.png