鸿蒙UI开发——实现一个上拉抽屉效果
1、概 述
在项目开发中,我们可能会遇到临时交互的场景(即:弹出一个临时交互框,交互完毕后继续用户的主流程),效果如下:

在ArkUI中,此类弹出窗被称为“半模态页面”,ArkUI为我们提供了一套可以快速实现此效果的接口,本文针对此效果的实现做讨论。
2、接口定义
给组件绑定半模态页面,点击后显示模态页面。接口定义如下:
bindSheet(isShow: Optional<boolean>, builder: CustomBuilder, options?: SheetOptions)
用法类似如下(第5行代码):
build() {Column() {Button("点击我弹出上拉抽屉")// ... 其他属性.bindSheet($$this.isShow, this.myBuilder(), {// 三挡高度(默认是中间)detents: [SheetSize.MEDIUM, SheetSize.LARGE, 200],blurStyle: BlurStyle.Thick,showClose: true,title: { title: "抽屉标题", subtitle: "抽屉副标题" },})}.justifyContent(FlexAlign.Start).width('100%').height('100%')}
其中:
-
isShow是可以支持双向绑定的显示/隐藏的切换控制;
-
builder是抽屉需要显示的内容,内容构造器;
-
options是配置参数,定义如下:
| 名称 | 类型 | 说明 |
| backgroundColor | ResourceColor | 半模态页面的背板颜色。默认值:Color.White。 |
| onWillAppear | () => void | 半模态页面显示(动画开始前)回调函数。 |
| onAppear | () => void | 半模态页面显示(动画结束后)回调函数。 |
| onWillDisappear | () => void | 半模态页面回退(动画开始前)回调函数。 |
| onDisappear | () => void | 半模态页面回退(动画结束后)回调函数。 |
| height | SheetSize | Length | 半模态高度,默认是LARGE。 |
| detents | [(SheetSize | Length), ( SheetSize | Length)?, (SheetSize | Length)?] | 半模态页面的切换高度档位。 |
| preferType | SheetType | 半模态页面的样式。 |
| showClose | boolean | Resource | 是否显示关闭图标,默认显示。 |
| dragBar | boolean | 是否显示控制条。 |
| blurStyle | BlurStyle | 半模态面板的模糊背景。默认无模糊背景。 |
| maskColor | ResourceColor | 半模态页面的背景蒙层颜色。 |
| title | SheetTitleOptions | CustomBuilder | 半模态面板的标题。 |
| enableOutsideInteractive | boolean | 半模态所在页面是否允许交互。 |
| shouldDismiss | (sheetDismiss: SheetDismiss) => void | 半模态页面交互式关闭回调函数。 |
| onWillDismiss | DismissSheetAction | 半模态页面交互式关闭回调函数。说明:当用户执行关闭操作时,如果注册该回调函数,不会立刻关闭, 由开发者控制是否关闭。在回调函数中可以通过reason得到关闭页面的操作类型,从而根据原因选择是否关闭半模态页面。在onWillDismiss回调中,不能再做onWillDismiss拦截。元服务API: 从API version 12开始,该接口支持在元服务中使用。 |
| onWillSpringBackWhenDismiss | SpringBackAction | 半模态页面交互式关闭前控制回弹函数。 |
| onHeightDidChange | Callback<number> | 半模态页面高度变化回调函数。 |
| onDetentsDidChange | Callback<number> | 半模态页面档位变化回调函数。 |
| onWidthDidChange | Callback<number> | 半模态页面宽度变化回调函数。 |
| onTypeDidChange | Callback<SheetType> | 半模态页面形态变化回调函数。 |
| borderWidth | Dimension | EdgeWidths | LocalizedEdgeWidths | 设置半模态页面的边框宽度。可分别设置4个边框宽度。默认值:0。百分比参数方式:以父元素半模态页面宽的百分比来设置半模态页面的边框宽度。当半模态页面左边框和右边框大于半模态页面宽度,半模态页面上边框和下边框大于半模态页面高度,显示可能不符合预期。说明:底部弹窗时,底部边框宽度设置无效。 |
| borderColor | ResourceColor | EdgeColors | LocalizedEdgeColors | 设置半模态页面的边框颜色。默认值:Color.Black。如果使用borderColor属性,需要和borderWidth属性一起使用。说明:底部弹窗时,底部边框颜色设置无效。 |
| borderStyle | BorderStyle | EdgeStyles | 设置半模态页面的边框样式。默认值:BorderStyle.Solid。如果使用borderStyle属性,需要和borderWidth属性一起使用。说明:底部弹窗时,底部边框样式设置无效。 |
| width | Dimension | 设置半模态页面的宽度。百分比参数方式:以父元素宽的百分比来设置半模态页面的宽度。 |
| shadow | ShadowOptions | ShadowStyle | 设置半模态页面的阴影。 |
| uiContext | UIContext | 在UIContext实例对应的窗口中显示半模态。说明:使用openBindSheet启动的半模态页面,不支持设置、更新该属性。元服务API: 从API version 12开始,该接口支持在元服务中使用。 |
| mode | SheetMode | 设置半模态页面的显示层级。默认值:SheetMode.OVERLAY。 |
| scrollSizeMode | ScrollSizeMode | 设置半模态面板滑动时,内容区域刷新时机。默认值:ScrollSizeMode.FOLLOW_DETENT 。 |
3、案 例
实现一个案例效果如下:

代码如下(24~30行的配置,5~15行的builder):
@Entry@Componentstruct SheetTransitionExample {@State isShow: boolean = false@BuildermyBuilder() {Column() {Text('欢迎加入【Harmony自习室】').fontSize(20)Button("确认").margin(10).fontSize(20)}.width('100%')}build() {Column() {Button("点击我弹出上拉抽屉").onClick(() => {this.isShow = true}).fontSize(20).margin(10).bindSheet($$this.isShow, this.myBuilder(), {// 三挡高度(默认是中间)detents: [SheetSize.MEDIUM, SheetSize.LARGE, 200],blurStyle: BlurStyle.Thick,showClose: true,title: { title: "抽屉标题", subtitle: "抽屉副标题" },})}.justifyContent(FlexAlign.Start).width('100%').height('100%')}}
