ArkUI RelativeContainer:复杂对齐别全靠嵌套
【摘要】 今天我们用 RelativeContainer 做几种相对定位:对齐容器、对齐兄弟组件,再补一个辅助线和屏障的小例子。 这篇不讲完整约束布局系统。我们先用一个小页面把锚点关系看清楚。 关键组件要有 id 在 RelativeContainer 里,组件之间要互相参考位置,就得先有稳定 id: container 表示容
ArkUI RelativeContainer:复杂对齐别全靠嵌套
今天我们用 RelativeContainer 做几种相对定位:对齐容器、对齐兄弟组件,再补一个辅助线和屏障的小例子。
这篇不讲完整约束布局系统。我们先用一个小页面把锚点关系看清楚。
关键组件要有 id
在 RelativeContainer 里,组件之间要互相参考位置,就得先有稳定 id:
Text('左侧')
.id('leftBadge')
.alignRules({
left: { anchor: '__container__', align: HorizontalAlign.Start },
center: { anchor: '__container__', align: VerticalAlign.Center }
})
__container__ 表示容器本身。这里的意思是:左边对齐容器左边,垂直中心对齐容器中心。
兄弟组件也能当锚点
第二个组件可以贴着第一个组件走:
Text('B 贴在 A 右侧')
.id('cardB')
.alignRules({
left: { anchor: 'cardA', align: HorizontalAlign.End },
top: { anchor: 'cardA', align: VerticalAlign.Top }
})
这类写法适合信息卡、头像加说明、局部操作区。它能减少一些无意义的 Row/Column 嵌套。
辅助线和屏障
guideLine 可以提供虚拟锚点,barrier 可以根据一组组件的边界生成参考线。先别把它想复杂,记住它们都是“给后面的对齐多一个参照物”。
你现在项目里有没有那种嵌套了很多层,只是为了让两个组件对齐的 UI?可以拿一小块出来试着改成 RelativeContainer。
完整代码
@Entry
@Component
struct ArkUIRelativeContainerDemo {
@Builder
sectionTitle(title: string, desc: string) {
Column({ space: 4 }) {
Text(title)
.width('100%')
.fontSize(16)
.fontWeight(700)
.fontColor('#0F172A')
Text(desc)
.width('100%')
.fontSize(13)
.fontColor('#64748B')
.lineHeight(20)
}
.width('100%')
.alignItems(HorizontalAlign.Start)
}
@Builder
badge(text: string, color: string) {
Text(text)
.height(36)
.padding({ left: 12, right: 12 })
.fontSize(13)
.fontWeight(700)
.fontColor('#FFFFFF')
.textAlign(TextAlign.Center)
.backgroundColor(color)
.borderRadius(8)
}
build() {
Scroll() {
Column({ space: 18 }) {
Text('ArkUI RelativeContainer')
.width('100%')
.fontSize(24)
.fontWeight(700)
.fontColor('#0F172A')
Text('复杂对齐别全靠嵌套')
.width('100%')
.fontSize(22)
.fontWeight(700)
.fontColor('#111827')
Text('RelativeContainer 适合处理多个元素互相参考位置的页面片段。这里只看锚点、辅助线和简单屏障,不展开完整约束系统。')
.width('100%')
.fontSize(14)
.fontColor('#64748B')
.lineHeight(22)
Column({ space: 12 }) {
this.sectionTitle('先给关键组件写 id', 'RelativeContainer 里要互相对齐,组件就要有稳定 id。没有 id 的组件,别人就没法拿它当锚点。')
RelativeContainer() {
Text('顶部居中')
.height(36)
.padding({ left: 12, right: 12 })
.fontSize(13)
.fontWeight(700)
.fontColor('#FFFFFF')
.textAlign(TextAlign.Center)
.backgroundColor('#2563EB')
.borderRadius(8)
.id('topBadge')
.alignRules({
top: { anchor: '__container__', align: VerticalAlign.Top },
middle: { anchor: '__container__', align: HorizontalAlign.Center }
})
Text('左侧')
.height(36)
.padding({ left: 12, right: 12 })
.fontSize(13)
.fontWeight(700)
.fontColor('#FFFFFF')
.textAlign(TextAlign.Center)
.backgroundColor('#0F766E')
.borderRadius(8)
.id('leftBadge')
.alignRules({
left: { anchor: '__container__', align: HorizontalAlign.Start },
center: { anchor: '__container__', align: VerticalAlign.Center }
})
Text('右侧')
.height(36)
.padding({ left: 12, right: 12 })
.fontSize(13)
.fontWeight(700)
.fontColor('#FFFFFF')
.textAlign(TextAlign.Center)
.backgroundColor('#C2410C')
.borderRadius(8)
.id('rightBadge')
.alignRules({
right: { anchor: '__container__', align: HorizontalAlign.End },
center: { anchor: '__container__', align: VerticalAlign.Center }
})
Text('底部居中')
.height(36)
.padding({ left: 12, right: 12 })
.fontSize(13)
.fontWeight(700)
.fontColor('#FFFFFF')
.textAlign(TextAlign.Center)
.backgroundColor('#7C3AED')
.borderRadius(8)
.id('bottomBadge')
.alignRules({
bottom: { anchor: '__container__', align: VerticalAlign.Bottom },
middle: { anchor: '__container__', align: HorizontalAlign.Center }
})
}
.width('100%')
.height(220)
.padding(12)
.backgroundColor('#FFFFFF')
.border({ width: 1, color: '#DBEAFE' })
.borderRadius(8)
}
.width('100%')
.padding(16)
.backgroundColor('#EFF6FF')
.borderRadius(8)
Column({ space: 12 }) {
this.sectionTitle('兄弟组件也可以互相当锚点', '第二个组件不一定非得对齐容器,也可以贴着第一个组件的右边或下边走。复杂信息卡会经常用到。')
RelativeContainer() {
Text('A')
.width(56)
.height(56)
.fontSize(18)
.fontWeight(700)
.fontColor('#FFFFFF')
.textAlign(TextAlign.Center)
.backgroundColor('#2563EB')
.borderRadius(8)
.id('cardA')
.alignRules({
left: { anchor: '__container__', align: HorizontalAlign.Start },
top: { anchor: '__container__', align: VerticalAlign.Top }
})
Text('B 贴在 A 右侧')
.height(56)
.padding({ left: 12, right: 12 })
.fontSize(13)
.fontWeight(700)
.fontColor('#FFFFFF')
.textAlign(TextAlign.Center)
.backgroundColor('#0F766E')
.borderRadius(8)
.id('cardB')
.alignRules({
left: { anchor: 'cardA', align: HorizontalAlign.End },
top: { anchor: 'cardA', align: VerticalAlign.Top }
})
.margin({ left: 10 })
Text('C 贴在 A 下方')
.width(146)
.height(44)
.fontSize(13)
.fontWeight(700)
.fontColor('#FFFFFF')
.textAlign(TextAlign.Center)
.backgroundColor('#7C3AED')
.borderRadius(8)
.id('cardC')
.alignRules({
top: { anchor: 'cardA', align: VerticalAlign.Bottom },
left: { anchor: 'cardA', align: HorizontalAlign.Start }
})
.margin({ top: 10 })
}
.width('100%')
.height(130)
.padding(12)
.backgroundColor('#FFFFFF')
.border({ width: 1, color: '#CCFBF1' })
.borderRadius(8)
}
.width('100%')
.padding(16)
.backgroundColor('#F0FDFA')
.borderRadius(8)
Column({ space: 12 }) {
this.sectionTitle('辅助线和屏障适合统一对齐', 'guideLine 可以提供虚拟锚点。barrier 可以根据一组组件的边界生成参考线,避免后面的内容压上来。')
RelativeContainer() {
Text('左侧信息')
.width(112)
.height(54)
.fontSize(13)
.fontWeight(700)
.fontColor('#FFFFFF')
.textAlign(TextAlign.Center)
.backgroundColor('#C2410C')
.borderRadius(8)
.id('leftInfo')
.alignRules({
right: { anchor: 'middleLine', align: HorizontalAlign.Start },
top: { anchor: '__container__', align: VerticalAlign.Top }
})
.margin({ right: 8 })
Text('右侧信息更高')
.width(128)
.height(72)
.fontSize(13)
.fontWeight(700)
.fontColor('#FFFFFF')
.textAlign(TextAlign.Center)
.backgroundColor('#1D4ED8')
.borderRadius(8)
.id('rightInfo')
.alignRules({
left: { anchor: 'middleLine', align: HorizontalAlign.End },
top: { anchor: '__container__', align: VerticalAlign.Top }
})
.margin({ left: 8 })
Text('跟在屏障下面')
.width('100%')
.height(42)
.fontSize(13)
.fontWeight(700)
.fontColor('#334155')
.textAlign(TextAlign.Center)
.backgroundColor('#F1F5F9')
.borderRadius(8)
.alignRules({
top: { anchor: 'bottomBarrier', align: VerticalAlign.Bottom },
left: { anchor: '__container__', align: HorizontalAlign.Start }
})
.margin({ top: 12 })
}
.guideLine([
{ id: 'middleLine', direction: Axis.Vertical, position: { start: '50%' } }
])
.barrier([
{ id: 'bottomBarrier', direction: BarrierDirection.BOTTOM, referencedId: ['leftInfo', 'rightInfo'] }
])
.width('100%')
.height(150)
.padding(12)
.backgroundColor('#FFFFFF')
.border({ width: 1, color: '#FED7AA' })
.borderRadius(8)
}
.width('100%')
.padding(16)
.backgroundColor('#FFF7ED')
.borderRadius(8)
}
.width('100%')
.padding(20)
.alignItems(HorizontalAlign.Start)
}
.width('100%')
.height('100%')
.backgroundColor('#FFFFFF')
}
}
【版权声明】本文为华为云社区用户原创内容,未经允许不得转载,如需转载请自行联系原作者进行授权。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)