鸿蒙UI开发——实现一个上拉抽屉效果

发布于:2025-05-22 ⋅ 阅读:(27) ⋅ 点赞:(0)

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

半模态页面回退(动画开始前)回调函数。

说明:不允许在onWillDisappear函数中修改状态变量,可能会导致组件行为不稳定。

onDisappear

() => void

半模态页面回退(动画结束后)回调函数。

height

SheetSize | Length

半模态高度,默认是LARGE。

说明:API version 12之前,底部弹窗横屏时该属性设置无效,高度为距离屏幕顶部8vp。API version 12开始,底部弹窗横屏时该属性设置生效,最大高度为距离屏幕顶部8vp。底部弹窗时,当设置detents时,该属性设置无效。底部弹窗竖屏时,最大高度为距离信号栏8vp。居中弹窗和跟手弹窗设置类型为SheetSize.LARGE和SheetSize.MEDIUM无效,显示默认高度560vp。居中弹窗和跟手弹窗最小高度为320vp,最大高度为窗口短边的90%。当使用Length设置的高度和使用SheetSize.FIT_CONTENT自适应的高度大于最大高度,则显示最大高度,小于最小高度,则显示最小高度。

detents

[(SheetSize | Length), ( SheetSize | Length)?, (SheetSize | Length)?]

半模态页面的切换高度档位。

说明:从API version 12开始,底部弹窗横屏时该属性设置生效。底部弹窗竖屏生效,元组中第一个高度为初始高度。面板可跟手滑动切换档位,松手后是否滑动至目标档位有两个判断条件:速度和距离。速度超过阈值,则执行滑动至与手速方向一致的目标档位;速度小于阈值,则引入距离判断条件,当位移距离>当前位置与目标位置的1/2,滑动至与手速方向一致的目标档位,位移距离当前位置与目标位置的1/2,返回至当前档位。速度阈值:1000,距离阈值:50%。

preferType

SheetType

半模态页面的样式。

说明:半模态在不同窗口所支持的显示类型:1. 宽度 < 600vp:底部。2. 600vp <= 宽度 < 840vp:底部、居中。默认居中样式。3. 宽度 >= 840vp:底部、居中、跟手。默认跟手样式。

showClose

boolean | Resource

是否显示关闭图标,默认显示。

说明:Resource需要为boolean类型。

dragBar

boolean

是否显示控制条。

说明:半模态面板的detents属性设置多个不同高度并且设置生效时,默认显示控制条。否则不显示控制条。

blurStyle

BlurStyle

半模态面板的模糊背景。默认无模糊背景。

maskColor

ResourceColor

半模态页面的背景蒙层颜色。

title

SheetTitleOptions | CustomBuilder

半模态面板的标题。

enableOutsideInteractive

boolean

半模态所在页面是否允许交互。

说明:设置为true时允许交互,不显示蒙层;设置为false时不允许交互,显示蒙层;若不进行设置,默认底部弹窗与居中弹窗不允许交互,跟手弹窗允许交互。当设置为true时,maskColor设置无效。

shouldDismiss

(sheetDismiss: SheetDismiss) => void

半模态页面交互式关闭回调函数。

说明:当用户执行下拉关闭/back事件/点击蒙层关闭/关闭按钮关闭交互操作时,如果注册该回调函数,则不会立刻关闭。

onWillDismiss

DismissSheetAction

半模态页面交互式关闭回调函数。说明:当用户执行关闭操作时,如果注册该回调函数,不会立刻关闭, 由开发者控制是否关闭。在回调函数中可以通过reason得到关闭页面的操作类型,从而根据原因选择是否关闭半模态页面。在onWillDismiss回调中,不能再做onWillDismiss拦截。元服务API: 从API version 12开始,该接口支持在元服务中使用。

onWillSpringBackWhenDismiss

SpringBackAction

半模态页面交互式关闭前控制回弹函数。

说明:当用户执行下拉关闭操作并注册shouldDimiss或onWillDismiss时,如果注册该回调函数,则不会回弹,由开发者控制下滑关闭时是否回弹。在回调函数中可以通过调用springBack来实现回弹效果。

onHeightDidChange

Callback<number>

半模态页面高度变化回调函数。

说明:底部弹窗时,只有档位变化和拖拽跟手才返回每一帧高度,拉起半模态和避让软键盘只返回最后的高度,其他弹窗只在半模态拉起返回最后高度。返回值为px。

onDetentsDidChange

Callback<number>

半模态页面档位变化回调函数。

说明:底部弹窗时,档位变化返回最后的高度。返回值为px。

onWidthDidChange

Callback<number>

半模态页面宽度变化回调函数。

说明:宽度变化时返回最后的宽度。返回值为px。

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。

说明:1. 半模态显示期间mode属性不支持动态切换,两种模式的显示层级完全不同,无法做到显示期间同一个半模态从一个层级变换到另一个层级。建议在使用时明确诉求固定mode值。2. 设置SheetMode.EMBEDDED时不支持设置UIContext属性,两者对应的半模态显示层级效果互相冲突。3. 使用openBindSheet启动半模态页面,若未传入有效的targetId,则不支持设置为SheetMode.EMBEDDED,默认为SheetMode.OVERLAY。元服务API: 从API version 12开始,该接口支持在元服务中使用。

scrollSizeMode

ScrollSizeMode

设置半模态面板滑动时,内容区域刷新时机。默认值:ScrollSizeMode.FOLLOW_DETENT 。

3、案 例

实现一个案例效果如下:

图片

代码如下(24~30行的配置,5~15行的builder):​​​​​​​

@Entry@Componentstruct SheetTransitionExample {  @State isShow: boolean = false  @Builder  myBuilder() {    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%')  }}