定义:半模态页面是一种多形态弹窗组件,支持在设备不同宽度下显示不同样式。用户可通过侧滑、点击蒙层/关闭按钮、下拉手势关闭页面,常用于扩展内容展示(如抽屉式面板)。
核心特性:
- 多形态适配:根据设备宽度自动调整样式。
- 灵活关闭方式:支持侧滑、蒙层点击、按钮关闭、下拉关闭。
- 交互控制:嵌套滚动支持、多档位高度、生命周期管理。
例如图中所示:
二、核心 API:bindSheet()
方法签名
bindSheet(
isShow: Optional<boolean>, // 控制显示/隐藏(支持 $$ 双向绑定)
builder: CustomBuilder, // 自定义内容构建器
options?: SheetOptions // 配置项(可选)
): T
参数说明
参数 |
类型 |
必填 |
说明 |
|
|
是 |
控制显示状态: |
|
|
是 |
自定义半模态内容(通过 |
|
|
否 |
配置半模态属性(高度、背景色、生命周期等) |
三、基础使用示例
场景:点击按钮弹出半模态页面
@Entry
@Component
struct SheetExample {
@State isShow: boolean = false;
// 自定义半模态内容
@Builder
myBuilder() {
Column() {
Button("关闭面板")
.onClick(() => this.isShow = false) // 点击关闭
}
.width('100%').height('100%')
}
build() {
Column() {
Button("打开半模态")
.onClick(() => this.isShow = true)
.bindSheet(
$$this.isShow,
this.myBuilder(),
{ height: 300, backgroundColor: Color.Gray }
)
}
}
}
通过.bindSheet()
方法将半模态页面绑定到Button组件上,其中:
$$this.isShow
实现双向数据绑定,自动同步半模态的显示状态this.myBuilder()
使用@Builder
装饰器定义的UI构建函数,描述半模态内部内容结构
运行截图:
四、嵌套滚动交互
当半模态容器内包含可滚动组件(如List)时,手势操作可能同时影响两个层级:
- 容器层级:面板高度调整/关闭操作
- 内容层级:内部组件滚动
通过嵌套滚动交互规则,可精确控制手势响应的优先级:
- 上滑/下滑时决定优先处理面板操作还是内容滚动
- 根据内容当前位置动态调整响应策略(顶部/中间/底部)
- 使用
nestedScroll()
配置实现精细控制
交互规则
当半模态内部有可滚动组件(如 List
)时:
- 内容在顶部:
-
- 上滑 → 优先扩展面板高度(若有更高档位)
- 下滑 → 优先收缩面板或关闭
- 内容在中间:
-
- 优先滚动内容,直到内容到达顶部/底部
- 内容在底部:
-
- 上滑 → 内容回弹(不切换档位)
- 下滑 → 滚动内容到顶部
关键配置
在内部滚动组件设置 嵌套滚动属性:
List() {
// 列表内容...
}
.nestedScroll({
scrollForward: NestedScrollMode.PARENT_FIRST, // 上滑优先处理面板
scrollBackward: NestedScrollMode.SELF_FIRST // 下滑优先处理列表
})
完整示例
@Entry
@Component
struct NestedScrollSheet {
@State isShow: boolean = false;
private data: number[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
@Builder
sheetContent() {
List({ space: '10vp' }) {
ForEach(this.data, (item:number) => {
ListItem() { Text(String(item)).fontSize(16).fontWeight(FontWeight.Bold) }
.width('90%').height('80vp').backgroundColor('#ff53ecd9').borderRadius(10)
})
}
.alignListItem(ListItemAlign.Center)
.margin({ top: '10vp' })
.width('100%')
.height('100%')
.nestedScroll({ // 关键配置
scrollForward: NestedScrollMode.PARENT_FIRST,
scrollBackward: NestedScrollMode.SELF_FIRST
})
}
build() {
Column() {
Button("打开带嵌套滚动的面板")
.onClick(() => this.isShow = true)
.bindSheet($$this.isShow, this.sheetContent(), {
detents: [200, 400, 600] // 定义三个高度档位
})
}
}
}
五、生命周期管理
半模态提供完整的生命周期回调:
回调函数 |
触发时机 |
典型用途 |
|
面板显示前(动画开始前) |
初始化数据 |
|
面板显示后(动画结束后) |
触发动态操作 |
|
面板关闭前(动画开始前) |
数据备份/清理 |
|
面板关闭后(动画结束后) |
资源释放 |
使用示例
Button("打开面板")
.bindSheet($$this.isShow, this.myBuilder(), {
onWillAppear: () => console.log("即将显示"),
onAppear: () => console.log("已显示"),
onWillDisappear: () => console.log("即将关闭"),
onDisappear: () => console.log("已关闭")
})
六、高级功能
1. 多档位高度(Detents)
支持预定义多个高度档位,用户可拖拽切换:
bindSheet($$this.isShow, builder, {
detents: [
SheetSize.SMALL, // 系统小尺寸
SheetSize.MEDIUM, // 系统中尺寸
450, // 自定义高度(vp)
SheetSize.LARGE // 系统大尺寸
]
})
2. 二次确认关闭
防止误触关闭,需用户确认:
bindSheet($$this.isShow, builder, {
// 第一步:声明onWillDismiss回调
onWillDismiss: ((DismissSheetAction: DismissSheetAction) => {
// 第二步:确认二次回调交互能力,此处用AlertDialog提示 "是否需要关闭半模态"
this.getUIContext().showAlertDialog(
{
message: '是否选择关闭半模态',
autoCancel: true,
alignment: DialogAlignment.Bottom,
gridCount: 4,
offset: { dx: 0, dy: -20 },
primaryButton: {
value: 'cancel',
action: () => {
console.info('Callback when the cancel button is clicked');
}
},
secondaryButton: {
enabled: true,
defaultFocus: true,
style: DialogButtonStyle.HIGHLIGHT,
value: 'ok',
// 第三步:确认关闭半模态逻辑所在,此处为AlertDialog的Button回调
action: () => {
// 第四步:上述第三步逻辑触发的时候,调用dismiss()关闭半模态
DismissSheetAction.dismiss();
console.info('Callback when the ok button is clicked');
}
},
cancel: () => {
console.info('AlertDialog Closed callbacks');
}
}
)
})
})