HarmonyOS7 浮层位置图谱:PopupPlacementAtlas
·
前言
Popup 最大的特点之一,就是它和触发组件有明确的空间关系。它不是简单地“出现在屏幕上”,而是可以出现在组件上方、下方、左侧或右侧。这个位置关系决定了用户是否能快速理解“这块浮层是在解释谁、服务谁”。
这个案例通过四个方向按钮,把 Placement 的常见取值一次讲清楚,特别适合做 Popup 位置能力的入门训练。
页面效果
案例将四个按钮排成一个十字结构:
- 顶部
- 左侧
- 右侧
- 底部
点击每个按钮,都会在对应方向弹出相同内容的 Popup,从而直观看到位置差异。
完整代码
import { DEMO_CARD_COLOR } from './types'
@Entry
@Component
struct PopupPlacementAtlas {
@State isShow: boolean = true
@State showTop: boolean = false
@State showBottom: boolean = false
@State showLeft: boolean = false
@State showRight: boolean = false
build() {
Column() {
if (this.isShow) {
Column() {
Text('Popup 位置演示')
.fontSize(16)
.fontWeight(FontWeight.Bold)
.margin({ bottom: 20 })
Row() {
Text('').layoutWeight(1)
Button('顶部')
.width(100)
.height(44)
.backgroundColor('#FF6B6B')
.borderRadius(10)
.fontColor('#FFFFFF')
.fontSize(14)
.bindPopup(this.showTop, {
builder: this.positionPopup(),
placement: Placement.Top,
enableArrow: true,
onStateChange: (e) => {
if (!e.isVisible) {
this.showTop = false
}
}
})
.onClick(() => {
this.showTop = !this.showTop
})
Text('').layoutWeight(1)
}
.width('100%')
.margin({ bottom: 12 })
Row() {
Button('左')
.width(70)
.height(44)
.backgroundColor('#4D96FF')
.borderRadius(10)
.fontColor('#FFFFFF')
.fontSize(14)
.bindPopup(this.showLeft, {
builder: this.positionPopup(),
placement: Placement.Left,
enableArrow: true,
onStateChange: (e) => {
if (!e.isVisible) {
this.showLeft = false
}
}
})
.onClick(() => {
this.showLeft = !this.showLeft
})
Text('').layoutWeight(1)
Button('右')
.width(70)
.height(44)
.backgroundColor('#6BCB77')
.borderRadius(10)
.fontColor('#FFFFFF')
.fontSize(14)
.bindPopup(this.showRight, {
builder: this.positionPopup(),
placement: Placement.Right,
enableArrow: true,
onStateChange: (e) => {
if (!e.isVisible) {
this.showRight = false
}
}
})
.onClick(() => {
this.showRight = !this.showRight
})
}
.width('100%')
.margin({ bottom: 12 })
Row() {
Text('').layoutWeight(1)
Button('底部')
.width(100)
.height(44)
.backgroundColor('#FFA500')
.borderRadius(10)
.fontColor('#FFFFFF')
.fontSize(14)
.bindPopup(this.showBottom, {
builder: this.positionPopup(),
placement: Placement.Bottom,
enableArrow: true,
onStateChange: (e) => {
if (!e.isVisible) {
this.showBottom = false
}
}
})
.onClick(() => {
this.showBottom = !this.showBottom
})
Text('').layoutWeight(1)
}
.width('100%')
}
.width('100%')
.padding(24)
.backgroundColor(DEMO_CARD_COLOR)
.borderRadius(12)
}
}
.width('100%')
.height('100%')
.backgroundColor('#F5F6FA')
.padding(16)
}
@Builder
positionPopup() {
Column() {
Text('Popup 内容')
.fontSize(14)
.fontColor('#333333')
}
.padding(12)
.backgroundColor('#FFFFFF')
.borderRadius(8)
.shadow({ radius: 8, color: '#00000010' })
}
}
关键代码讲解
1. Placement 决定浮层的方向关系
案例里分别使用了四种位置:
Placement.TopPlacement.LeftPlacement.RightPlacement.Bottom
这不是简单的视觉摆放,而是在告诉系统:Popup 应该相对于触发组件从哪个方向展开。
2. 十字布局很适合教学和调试
这个案例把按钮刻意排成了十字结构,目的很明确:让你在一个页面里同时观察四个方向的行为。平时业务开发虽然不一定这么排,但在调试浮层位置时,这种布局很有效。
3. 同一份内容可以复用到不同位置
四个按钮都复用了 positionPopup()。这说明位置和内容本身是可以分开的:
- 内容关注展示什么
- 位置关注从哪里弹出
当你以后做帮助提示、标签说明、状态解释时,这种解耦方式会非常省事。
如何选择方向
一般可以这样判断:
- 上方空间充足,用
Top - 下方承接内容更自然,用
Bottom - 列表项右侧有更多操作,用
Right - 左右结构中需要说明前置内容,用
Left
别只凭视觉喜好选方向,应该优先考虑空间和阅读路径。
总结
这个案例把 Popup 的方向能力拆得很直白。真正要掌握的是:位置不是装饰,而是上下文关系的一部分。当浮层方向和用户视线运动一致时,交互理解成本会低很多。
更多推荐

所有评论(0)