鸿蒙 ArkTS 布局深入浅出:Panel 组件三种模式(Mini / Half / Full)完全解析
鸿蒙 ArkTS 布局深入浅出:Panel 组件三种模式(Mini / Half / Full)完全解析



前言
在 HarmonyOS NEXT(API 24)的应用开发中,UI 布局是绕不开的核心话题。ArkTS 作为鸿蒙原生声明式开发语言,提供了一系列强大且易用的布局组件。其中,Panel(面板)组件 是一个非常实用的容器类控件——它从屏幕底部滑入,支持三种高度模式切换,广泛应用于播放器、设置面板、评论区域等需要「展开-收起」交互的场景。
本文将围绕 Panel 的三种模式——Mini(最小)、Half(半屏) 和 Full(全屏)——展开详细讲解,并附上完整可运行的示例代码,帮助读者快速掌握这一布局利器。
一、Panel 组件概述
1.1 什么是 Panel
Panel 是 ArkUI 提供的一种可拖拽、可切换高度模式的底部面板组件。与传统的 Dialog 或 BottomSheet 不同,Panel 具有以下特性:
- 三种预设高度模式:迷你、半屏、全屏,可通过代码或手势切换
- 内置拖拽条(dragBar):用户可直接拖拽面板边缘切换模式
- 灵活的高度自定义:每种模式均可独立设置高度值
- 圆角和阴影支持:视觉层次感强
- 回调监听完善:模式变化、可见性变化均可捕捉
1.2 适用场景
| 场景 | 推荐模式 | 说明 |
|---|---|---|
| 音乐播放器迷你栏 | Mini | 展示歌曲名 + 播放控制按钮 |
| 评论列表 / 弹幕面板 | Half | 半屏展示,留出内容区域 |
| 商品详情 / 文章阅读 | Full | 全屏沉浸式浏览 |
| 设置选项 / 筛选器 | Half | 半屏表单,操作后自动收起 |
| 地图底部的路线面板 | Half → Full | 拖拽渐变展开 |
二、Panel 三种模式详解
Panel 的核心能力围绕 PanelMode 枚举展开。API 24 中该枚举的三个成员为:PanelMode.Mini、PanelMode.Half、PanelMode.Full。
注意:早期 API(如 API 11~12)中枚举值名为
MIN/HALF/FULL(全大写),API 24 统一为 PascalCase 风格Mini/Half/Full,迁移时需相应调整。
Mini 模式
面板的最小高度形态,由 .miniHeight() 属性控制(单位为 vp)。适用于展示简短的提示信息、播放器迷你控制栏、通知预览等轻量场景。
Half 模式
面板展开至屏幕约一半高度,由 .halfHeight() 属性控制(支持百分比与数值)。适用于列表选择器、评论输入区域、配置选项面板等中等体量的内容。
Full 模式
面板几乎占满屏幕(通常 90%~95%),由 .fullHeight() 属性控制。适用于详情展示页面、编辑器和媒体全屏控制面板等需要大面积展示的场景。
三种模式之间可以通过手势拖拽无缝切换,体验流畅自然。
三、项目实战:三种模式切换演示
3.1 核心代码实现
以下为基于 API 24 的 Panel 演示页面的完整实现,已通过 hvigorw assembleApp 编译验证。
@Entry
@Component
struct PanelDemo {
@State isPanelShow: boolean = false;
@State currentMode: PanelMode = PanelMode.Mini;
@State modeLabel: string = 'Mini(最小)';
private readonly modeList: PanelMode[] = [
PanelMode.Mini, PanelMode.Half, PanelMode.Full
];
private readonly modeLabels: string[] = [
'Mini(最小)', 'Half(半屏)', 'Full(全屏)'
];
switchToNextMode(): void {
const i = this.modeList.indexOf(this.currentMode);
const next = (i + 1) % this.modeList.length;
this.currentMode = this.modeList[next];
this.modeLabel = this.modeLabels[next];
}
setMode(mode: PanelMode, label: string): void {
this.currentMode = mode;
this.modeLabel = label;
if (!this.isPanelShow) this.isPanelShow = true;
}
build() {
Stack() {
// 背景内容区域
Column() {
Text('Panel 三种模式演示')
.fontSize(24).fontWeight(FontWeight.Bold).margin({ top: 24 });
Text(`当前模式:${this.modeLabel}`)
.fontSize(18).margin({ top: 12, bottom: 24 });
// 方式一:轮换切换
Button('切换至下一模式')
.width('90%').height(48).type(ButtonType.Capsule)
.backgroundColor('#FF007AFF').fontColor(Color.White)
.onClick(() => { this.switchToNextMode(); this.isPanelShow = true; })
.margin({ bottom: 24 });
// 方式二:直接跳转
Row() {
Button('MIN').height(44).layoutWeight(1).type(ButtonType.Capsule)
.backgroundColor(this.currentMode === PanelMode.Mini
? '#FF007AFF' : '#FFCCCCCC')
.onClick(() => this.setMode(PanelMode.Mini, 'Mini(最小)'));
Button('HALF').height(44).layoutWeight(1).type(ButtonType.Capsule)
.backgroundColor(this.currentMode === PanelMode.Half
? '#FF007AFF' : '#FFCCCCCC')
.onClick(() => this.setMode(PanelMode.Half, 'Half(半屏)'));
Button('FULL').height(44).layoutWeight(1).type(ButtonType.Capsule)
.backgroundColor(this.currentMode === PanelMode.Full
? '#FF007AFF' : '#FFCCCCCC')
.onClick(() => this.setMode(PanelMode.Full, 'Full(全屏)'));
}.width('90%').margin({ bottom: 24 });
}.width('100%').height('100%').backgroundColor('#FFF5F5F5');
// Panel 组件
Panel(this.isPanelShow) {
Column() {
Text('▼ 向上拖拽可切换模式').fontSize(14).margin({ top: 8 });
Text('面板内容区').fontSize(20).fontWeight(FontWeight.Bold);
Text(this.modeLabel).fontSize(28).fontColor('#FF007AFF');
if (this.currentMode === PanelMode.Mini) {
this.modeDesc('Mini', '面板仅展示最小高度内容。');
} else if (this.currentMode === PanelMode.Half) {
this.modeDesc('Half', '面板展开至屏幕一半高度。');
} else {
this.modeDesc('Full', '面板几乎填满整个屏幕。');
}
}.width('100%').padding({ left: 16, right: 16, bottom: 24 });
}
.mode(this.currentMode)
.dragBar(true)
.miniHeight(200)
.halfHeight('50%')
.fullHeight('90%')
.backgroundColor('#FFFFFFFF')
.borderRadius(20)
.onChange((m: PanelMode): void => {
this.currentMode = m;
const idx = this.modeList.indexOf(m);
if (idx !== -1) this.modeLabel = this.modeLabels[idx];
})
.onVisibleAreaChange([0.0, 0.5, 1.0],
(v: boolean): void => { this.isPanelShow = v; })
.shadow({ radius: 16, color: 'rgba(0,0,0,0.15)',
offsetX: 0, offsetY: -4 });
}.width('100%').height('100%').alignContent(Alignment.Bottom);
}
@Builder
modeDesc(title: string, desc: string): void {
Column() {
Text(title).fontSize(16).fontWeight(FontWeight.Medium);
Text(desc).fontSize(14).fontColor('#FF666666').lineHeight(22);
}.width('90%').padding(16).backgroundColor('#FFF0F4FF')
.borderRadius(12).margin({ top: 8, bottom: 8 });
}
}
3.2 页面路由注册
在 resources/base/profile/main_pages.json 中:
{ "src": ["pages/Index", "pages/PanelDemo"] }
四、核心 API 深度解读
4.1 构造函数
Panel(value: boolean)
API 24 接受直接布尔值,不再支持 { show: boolean } 对象字面量。
4.2 关键属性
| 属性方法 | 说明 | 示例值 |
|---|---|---|
.mode(PanelMode) |
设置面板高度模式 | PanelMode.Half |
.miniHeight(length) |
Mini 模式高度(vp) | 200 |
.halfHeight(len | str) |
Half 模式高度 | '50%' 或 400 |
.fullHeight(len | str) |
Full 模式高度 | '90%' 或 700 |
.dragBar(boolean) |
显示拖拽条 | true |
4.3 回调事件
| 回调 | 说明 | 参数 |
|---|---|---|
.onChange(cb) |
模式切换时触发 | (PanelMode) => void |
.onVisibleAreaChange(ratios, cb) |
可见比例变化时触发 | number[] + callback |
onVisibleAreaChange替代了旧版onVisibleChange,需额外传入阈值数组(如[0.0, 0.5, 1.0])。
五、API 24 迁移对照
从 API 11~12 迁移到 API 24 的核心变更:
| 旧 API(11~12) | 新 API(24) | 说明 |
|---|---|---|
Panel({ show }) |
Panel(bool) |
构造参数简化 |
PanelMode.MIN |
PanelMode.Mini |
PascalCase 统一 |
PanelMode.HALF |
PanelMode.Half |
同上 |
PanelMode.FULL |
PanelMode.Full |
同上 |
.minHeight(v) |
.miniHeight(v) |
属性重命名 |
.onVisibleChange(cb) |
.onVisibleAreaChange(ratios, cb) |
新增 ratios 参数 |
import { PanelMode } |
无需 import | 全局类型 |
六、最佳实践
高度单位选择
- Mini 模式推荐使用固定 vp 值(如
200),使内容紧凑可控 - Half / Full 模式推荐使用百分比字符串(如
'50%'),自适应屏幕
状态同步
务必实现 onChange 回调,将拖拽产生的模式变化同步到应用状态,避免「按钮显示 Half 而面板实际已到 Full」的不一致。
Stack 容器对齐
Panel 从底部弹出,包裹它的 Stack 容器应设为 alignContent(Alignment.Bottom)。
圆角与阴影
为 Panel 添加顶部圆角和阴影可显著提升视觉层次:
.borderRadius(20)
.shadow({ radius: 16, color: 'rgba(0,0,0,0.15)', offsetX: 0, offsetY: -4 })
七、扩展思路
与 List 结合
在 Panel 内部放置 List,实现可拖拽展开的评论列表或通知中心——最常用的生产级场景。
配合动画
结合 animateTo 在模式切换时添加内容自定义动画,进一步提升体验。
自定义拖拽条
设置 dragBar(false),用 PanGesture 自行实现拖拽手势区域,配合 onChange 完成模式切换,适合需要精致设计的场景。
八、总结
Panel 组件是 HarmonyOS NEXT 中极具实用价值的布局组件。它的三种高度模式——Mini、Half、Full——覆盖了从「轻量提示」到「全屏详情」的全场景需求。配合拖拽手势、灵活的样式定制和完备的回调体系,开发者只需少量代码就能构建出体验流畅的底部面板交互。
API 24 的命名变更虽然带来了一些迁移成本,但统一后的 PascalCase 风格使代码更加规整,与 ArkTS 整体语言风格保持一致。希望本文能帮助你在实际项目中高效地使用 Panel 组件。
更多推荐




所有评论(0)