ArkUI相对布局(RelativeContainer)详解(附带实例)
在应用的开发过程中,经常需要设计复杂界面,此时会涉及多个相同或不同组件之间的嵌套。如果布局组件嵌套深度过深,或嵌套组件数量过多,就会带来额外的性能开销。因此,需要在布局的方式上进行优化,以提升性能并减少时间开销。
RelativeContainer 是采用相对布局的容器,支持容器内部子元素设置的相对位置关系,适用于在界面复杂的场景中对多个子组件进行对齐和排列。子元素可以指定兄弟元素或父容器作为锚点,并基于锚点进行相对位置布局。
下图所示是一个 RelativeContainer 的概念图,图中的虚线表示位置的依赖关系。

图 1 相对布局示意图
子元素的依赖关系不一定完全如图 1 所示。比如,Item4 可以将 Item2 作为依赖锚点,也可以将 RelativeContainer 父容器作为依赖锚点。
这里先介绍 2 个基本概念:
在水平方向上,可以设置 left、middle、right 的锚点;在竖直方向上,可以设置 top、center、bottom 的锚点。
为了明确定义锚点,必须为 RelativeContainer 及其子元素设置 ID,以指定锚点信息。默认情况下,RelativeContainer 的 ID 为 __container__,其他子元素的 ID 需要通过 id 属性显式设置。未设置 ID 的组件仍可显示,但无法作为其他子组件的锚点。
对于未设置 ID 的组件,相对布局容器会自动为其生成一个 ID,但该 ID 的命名规则无法被外部应用感知。在涉及互相依赖或环形依赖时,容器内的所有子组件将无法绘制。同一方向上,如果有两个或以上的位置设置了锚点,并且锚点位置逆序时,相关子组件的大小将被设为 0,即不进行绘制。
在使用锚点时,要注意子元素的相对位置关系,避免出现错位或遮挡的情况。
以 RelativeContainer 父组件为锚点的相对布局示例代码如下:

图 2 以父组件为锚点的相对布局显示效果
以兄弟元素为锚点的相对布局示例代码如下:

图 3 以兄弟元素为锚点的相对布局显示效果
当以子组件为锚点时,子组件可以任意选择,但需注意不要相互依赖,示例代码如下:

图 4 使用子组件锚点的显示效果

图 5 水平方向上锚点的对齐位置
在竖直方向上,对齐位置可以设置为 VerticalAlign.Top、VerticalAlign.Center、VerticalAlign.Bottom,如下图所示,图中的黑线表示锚点。

图 6 竖直方向上锚点的对齐位置

图 7 使用子组件位置偏移后的显示效果
RelativeContainer 是采用相对布局的容器,支持容器内部子元素设置的相对位置关系,适用于在界面复杂的场景中对多个子组件进行对齐和排列。子元素可以指定兄弟元素或父容器作为锚点,并基于锚点进行相对位置布局。
下图所示是一个 RelativeContainer 的概念图,图中的虚线表示位置的依赖关系。

图 1 相对布局示意图
子元素的依赖关系不一定完全如图 1 所示。比如,Item4 可以将 Item2 作为依赖锚点,也可以将 RelativeContainer 父容器作为依赖锚点。
这里先介绍 2 个基本概念:
- 锚点:通过锚点设置当前元素基于哪个元素确定位置。
- 对齐方式:通过对齐方式设置当前元素是基于锚点的上中下对齐,还是基于锚点的左中右对齐。
锚点设置
锚点设置是指设置子元素相对于父元素或兄弟元素的位置依赖关系。在水平方向上,可以设置 left、middle、right 的锚点;在竖直方向上,可以设置 top、center、bottom 的锚点。
为了明确定义锚点,必须为 RelativeContainer 及其子元素设置 ID,以指定锚点信息。默认情况下,RelativeContainer 的 ID 为 __container__,其他子元素的 ID 需要通过 id 属性显式设置。未设置 ID 的组件仍可显示,但无法作为其他子组件的锚点。
对于未设置 ID 的组件,相对布局容器会自动为其生成一个 ID,但该 ID 的命名规则无法被外部应用感知。在涉及互相依赖或环形依赖时,容器内的所有子组件将无法绘制。同一方向上,如果有两个或以上的位置设置了锚点,并且锚点位置逆序时,相关子组件的大小将被设为 0,即不进行绘制。
在使用锚点时,要注意子元素的相对位置关系,避免出现错位或遮挡的情况。
以 RelativeContainer 父组件为锚点的相对布局示例代码如下:
// 相对布局规则设置 let AlignRus: Record<string, Record<string, string | VerticalAlign | HorizontalAlign>> = { // 顶部相对于容器顶部对齐 top: { anchor: '__container__', align: VerticalAlign.Top }, // 左侧相对于容器左对齐 left: { anchor: '__container__', align: HorizontalAlign.Start } }; // 相对布局规则设置 let AlignRue: Record<string, Record<string, string | VerticalAlign | HorizontalAlign>> = { // 顶部相对于容器顶部对齐 top: { anchor: '__container__', align: VerticalAlign.Top }, // 右侧相对于容器右对齐 right: { anchor: '__container__', align: HorizontalAlign.End } }; // 通过 Record 类型数据设置外边距参数 let MLeft: Record<string, number> = { left: 20 }; // 通过 Record 类型数据设置边框参数 let BWC: Record<string, number | string> = { width: 2, color: '#6699FF' }; @Entry @Component struct Index { build() { // 相对布局容器,默认 id 为 __container__ RelativeContainer() { Row() { Text('row1') .fontColor(Color.Yellow) // 子组件在水平方向居中对齐 .justifyContent(FlexAlign.Center) .width(100) .height(100) .backgroundColor('#FF3333') // 设置相对布局参数 .alignRules(AlignRus) // 组件 id 为 row1 .id('row1') } Row() { Text('row2') .fontColor(Color.White) // 设置子组件在水平方向居中对齐 .justifyContent(FlexAlign.Center) .width(100) .height(100) .backgroundColor('#000000') // 设置相对布局参数 .alignRules(AlignRue) // 组件 id 为 row2 .id('row2') } } .width(300) .height(300) // 设置外边距布局参数 .margin(MLeft) // 设置边框布局参数 .border(BWC) } }显示效果如下图所示:

图 2 以父组件为锚点的相对布局显示效果
以兄弟元素为锚点的相对布局示例代码如下:
// 设置相对布局规则:row1 相对于容器 let AlignRus: Record<string, Record<string, string | VerticalAlign | HorizontalAlign>> = { // 顶部相对于容器顶部对齐 'top': { 'anchor': '__container__', 'align': VerticalAlign.Top }, // 左侧相对于容器左侧对齐 'left': { 'anchor': '__container__', 'align': HorizontalAlign.Start } }; // 设置相对布局规则:row2 相对于 row1 let RelConB: Record<string, Record<string, string | VerticalAlign | HorizontalAlign>> = { // 顶部相对于 row1 元素底部对齐 'top': { 'anchor': 'row1', 'align': VerticalAlign.Bottom }, // 左侧相对于 row1 元素左对齐 'left': { 'anchor': 'row1', 'align': HorizontalAlign.Start } }; // 通过 Record 类型数据设置外边距参数 let MLeft: Record<string, number> = { left: 20 }; // 通过 Record 类型数据设置边框参数 let BWC: Record<string, number | string> = { width: 2, color: '#6699FF' }; @Entry @Component struct Index { build() { // 相对布局容器,默认 ID 为 __container__ RelativeContainer() { Row() { Text('row1') .fontColor(Color.White) // 子组件在水平方向居中对齐 .justifyContent(FlexAlign.Center) .width(100) .height(100) .backgroundColor('#FF3333') // 设置相对布局规则 .alignRules(AlignRus) // 组件 ID 为 row1 .id('row1') } // row2 Row() { Text('row2') .fontColor(Color.White) // 子组件在水平方向居中对齐 .justifyContent(FlexAlign.Center) .width(100) .height(100) .backgroundColor(Color.Black) // 设置相对布局规则 .alignRules(RelConB) // 组件 ID 为 row2 .id('row2') } } .width(300) .height(300) // 设置外边距参数 .margin(MLeft) // 设置边框参数 .border(BWC) } }显示效果如下图所示:

图 3 以兄弟元素为锚点的相对布局显示效果
当以子组件为锚点时,子组件可以任意选择,但需注意不要相互依赖,示例代码如下:
@Entry @Component struct Index { build() { // 相对布局容器,默认 id 为 __container__ RelativeContainer() { // ===== Row1 ===== Row() { Text('row1') .fontColor(Color.Yellow) // 子组件在水平方向居中对齐 .justifyContent(FlexAlign.Center) .width(100) .height(100) .backgroundColor('#ff3339ff') // 相对布局规则:顶部相对于父组件垂直方向顶部对齐 // 左侧相对于父组件水平方向左对齐 .alignRules({ top: { anchor: '__container__', align: VerticalAlign.Top }, left: { anchor: '__container__', align: HorizontalAlign.Start } }) // 组件 ID 为 row1 .id('row1') } Row() { Text('row2') .fontColor(Color.Yellow) .justifyContent(FlexAlign.Center) .width(100) .height(100) .backgroundColor('#ff298e1e') // 相对布局规则: .alignRules({ // 1) 顶部相对于父组件垂直方向顶部对齐 top: { anchor: '__container__', align: VerticalAlign.Top }, // 2) 右侧相对于父组件水平方向右对齐 right: { anchor: '__container__', align: HorizontalAlign.End }, // 3) 底部相对于 row1 元素垂直方向居中对齐(row2 底部对齐 row1 中间) bottom: { anchor: 'row1', align: VerticalAlign.Center } }) // 组件 ID 为 row2 .id('row2') } Row() { Text('row3') .justifyContent(FlexAlign.Center) .height(100) .backgroundColor('#ffff6a33') // 相对布局规则: .alignRules({ // 1) 顶部相对于 row1 底部对齐 top: { anchor: 'row1', align: VerticalAlign.Bottom }, // 2) 左侧相对于 row1 左对齐 left: { anchor: 'row1', align: HorizontalAlign.Start }, // 3) 右侧相对于 row2 左对齐 right: { anchor: 'row2', align: HorizontalAlign.Start } }) // 组件 ID 为 row3 .id('row3') } Row() { Text('row4') .justifyContent(FlexAlign.Center) .backgroundColor('#ffff33fd') // 相对布局规则: .alignRules({ // 1) 顶部对齐 row3 的底部 top: { anchor: 'row3', align: VerticalAlign.Bottom }, // 2) 左侧对齐 row1 的中间 left: { anchor: 'row1', align: HorizontalAlign.Center }, // 3) 右侧对齐 row2 的右边 right: { anchor: 'row2', align: HorizontalAlign.End }, // 4) 底部对齐容器的底部 bottom: { anchor: '__container__', align: VerticalAlign.Bottom } }) // 组件 ID 为 row4 .id('row4') } } .width(300) .height('100%') // 修正图片中高度符号为 '100%' // 设置外边距参数 .margin({ left: 50 }) // 设置边框参数 .border({ width: 2, color: '#6699FF' }) } }显示效果如下图所示:

图 4 使用子组件锚点的显示效果
设置相对于锚点的对齐位置
设置了锚点之后,可以通过 align 属性设置相对于锚点的对齐位置。在水平方向上,对齐位置可以设置为 HorizontalAlign.Start、HorizontalAlign.Center、HorizontalAlign.End,如下图所示,图中的黑线表示锚点。
图 5 水平方向上锚点的对齐位置
在竖直方向上,对齐位置可以设置为 VerticalAlign.Top、VerticalAlign.Center、VerticalAlign.Bottom,如下图所示,图中的黑线表示锚点。

图 6 竖直方向上锚点的对齐位置
子组件位置偏移
子组件经过相对位置对齐后,此时的位置可能还不是目标位置,开发者可根据需要使用 offset 属性进行额外的偏移设置,示例代码如下:@Entry @Component struct Index { build() { // 相对布局容器,默认 id 为 __container__ RelativeContainer() { // ===== Row1 ===== Row() { Text('row1') .justifyContent(FlexAlign.Center) .width(100) .height(100) .backgroundColor('#FF3333') // 相对布局规则:顶部与容器的顶部对齐,左侧与容器的左侧对齐 .alignRules({ top: { anchor: '__container__', align: VerticalAlign.Top }, left: { anchor: '__container__', align: HorizontalAlign.Start } }) // 组件 ID .id('row1') } // ===== Row2 ===== Row() { Text('row2') .justifyContent(FlexAlign.Center) .width(100) .height(100) .backgroundColor('#FFCC00') // 相对布局规则: .alignRules({ // 顶部与容器的顶部对齐 top: { anchor: '__container__', align: VerticalAlign.Top }, // 右侧与容器的右侧对齐 right: { anchor: '__container__', align: HorizontalAlign.End }, // 底部与 row1 的垂直方向中间对齐 bottom: { anchor: 'row1', align: VerticalAlign.Center } }) // 在原本的位置上,x 轴方向左移 40 vp,y 轴方向上移 20 vp .offset({ x: -40, y: -20 }) .id('row2') } // ===== Row3 ===== Row() { Text('row3') .justifyContent(FlexAlign.Center) .width(100) // 宽度在 12.jpg 已出现 .height(100) .backgroundColor('#FF6633') // 相对布局规则: .alignRules({ // 顶部与 row1 的底部对齐 top: { anchor: 'row1', align: VerticalAlign.Bottom }, // 左侧与 row1 的右侧对齐 left: { anchor: 'row1', align: HorizontalAlign.End }, // 右侧与 row2 的左边对齐 right: { anchor: 'row2', align: HorizontalAlign.Start } }) // 在原本的位置上,x 轴方向左移 10 vp,y 轴方向上移 20 vp .offset({ x: -10, y: -20 }) .id('row3') } // ===== Row4 ===== Row() { Text('row4') .justifyContent(FlexAlign.Center) .width(100) // 隐含宽度,补全保持一致 .height(100) .backgroundColor('#FF9966') // 相对布局规则: .alignRules({ // 顶部与 row3 的底部对齐 top: { anchor: 'row3', align: VerticalAlign.Bottom }, // 底部与容器的底部对齐 bottom: { anchor: '__container__', align: VerticalAlign.Bottom }, // 左边与容器的左边对齐 left: { anchor: '__container__', align: HorizontalAlign.Start }, // 右边与 row1 的右边对齐 right: { anchor: 'row1', align: HorizontalAlign.End } }) // 在原本的位置上,x 轴方向左移 10 vp,y 轴方向上移 30 vp .offset({ x: -10, y: -30 }) .id('row4') } // ===== Row5 ===== Row() { Text('row5') .justifyContent(FlexAlign.Center) .width(100) // 隐含宽度,补全保持一致 .height(100) .backgroundColor('#FF66FF') // 相对布局规则: .alignRules({ // 顶部与 row3 的底部对齐 top: { anchor: 'row3', align: VerticalAlign.Bottom }, // 底部与容器的底部对齐 bottom: { anchor: '__container__', align: VerticalAlign.Bottom }, // 左边与 row2 的左边对齐 left: { anchor: 'row2', align: HorizontalAlign.Start }, // 右边与 row2 的右边对齐 right: { anchor: 'row2', align: HorizontalAlign.End } }) // 在原本的位置上,x 轴方向右移 10 vp,y 轴方向下移 20 vp .offset({ x: 10, y: 20 }) .id('row5') } // ===== Row6 ===== Row() { Text('row6') .justifyContent(FlexAlign.Center) .width(100) .height(100) .backgroundColor('#ff33ffb5') // 相对布局规则: .alignRules({ // 顶部与 row3 的底部对齐 top: { anchor: 'row3', align: VerticalAlign.Bottom }, // 底部与 row4 的底部对齐 bottom: { anchor: 'row4', align: VerticalAlign.Bottom }, // 左边与 row3 的左边对齐 left: { anchor: 'row3', align: HorizontalAlign.Start }, // 右边与 row3 的右边对齐 right: { anchor: 'row3', align: HorizontalAlign.End } }) // 在原本的位置上,x 轴方向左移 15 vp,y 轴方向下移 10 vp .offset({ x: -15, y: 10 }) // 背景图位置与尺寸示例 .backgroundImagePosition(Alignment.Bottom) .backgroundImageSize(ImageSize.Cover) .id('row6') } } .width(300) .height('100%') // 修正图片中的全角/错误引号 .margin({ left: 50 }) .border({ width: 2, color: '#6699FF' }) } }显示效果如下图所示:

图 7 使用子组件位置偏移后的显示效果