【HarmonyOS实战】bindSheet半屏弹窗:打造流畅的底部抽屉效果
2026/6/5 14:59:14 网站建设 项目流程

文章目录

    • 前言
    • 一、bindSheet 的基本用法
    • 二、项目中的 bindSheet 实现
    • 三、参数详解
      • 3.1 $$this.isShow:双向绑定控制显示
      • 3.2 detents:弹窗高度配置
      • 3.3 dragBar:拖拽把手
      • 3.4 title:弹窗标题
      • 3.5 blurStyle:毛玻璃效果
      • 3.6 backgroundColor:背景颜色
      • 3.7 onWillDismiss:关闭前回调
    • 四、bindBuilder:弹窗内容
    • 五、弹窗的完整生命周期
    • 六、bindSheet vs 自定义弹窗
    • 总结

前言

"附近加油站"里有一个很好看的交互:进入地图页后,底部会滑出一个半透明的面板,展示附近的加油站列表。这个效果叫半屏弹窗(Bottom Sheet),在 HarmonyOS 里用bindSheet实现。

bindSheet是 ArkUI 里非常强大的 API,参数很多,但用对了能做出 iOS 级别的流畅体验。这篇文章把项目里的用法完整讲解,让你彻底掌握它。

项目预览

一、bindSheet 的基本用法

bindSheet是任何组件都可以调用的属性方法,语法:

组件.bindSheet($$isShow,// 双向绑定:控制弹窗显示/隐藏的状态变量builder(),// 弹窗内容:一个 @Builder 函数options// 配置项)

二、项目中的 bindSheet 实现

// GasStationPage.etsStack(){MapComponent({...});this.titleBuilder();}.width('100%').height('100%').bindSheet($$this.isShow,this.bindBuilder(),{// 弹窗高度锚点:支持两种高度detents:[Constants.BIND_SHEET_HEIGHT,SheetSize.MEDIUM],// 不显示拖拽把手dragBar:false,// 弹窗标题title:{title:$r('app.string.gas_station')},// 毛玻璃背景效果blurStyle:BlurStyle.COMPONENT_THICK,// 弹窗背景色(半透明白色)backgroundColor:$r('app.color.bind_sheet_background'),// 弹窗关闭前的回调onWillDismiss:((dismissSheetAction:DismissSheetAction)=>{if(this.curMarker){this.imageScale=1;mapUtil.imageAnimation(this.curMarker,this.imageScale);// 恢复 Marker 大小}dismissSheetAction.dismiss();// 确认关闭弹窗})});

三、参数详解

3.1 $$this.isShow:双向绑定控制显示

@StateisShow:boolean=false;// 使用 $$ 表示双向绑定.bindSheet($$this.isShow,...)

$$是 ArkUI 的"状态变量双向绑定"语法:

  • isShow = true:弹窗显示
  • isShow = false:弹窗关闭
  • 用户下拉关闭弹窗时,isShow也会自动变为false
// 触发显示弹窗(多处调用)this.isShow=true;// 页面进入1秒后自动显示setTimeout(()=>{this.isShow=true;},Constants.TIME);// 1000ms

3.2 detents:弹窗高度配置

detents:[Constants.BIND_SHEET_HEIGHT,SheetSize.MEDIUM]// = [400, SheetSize.MEDIUM]

detents是弹窗可以停留的高度锚点数组,用户可以拖拽在这些高度之间切换:

说明
number(如 400)固定高度(px)
SheetSize.FIT_CONTENT自适应内容高度
SheetSize.MEDIUM屏幕高度的 50%
SheetSize.LARGE屏幕高度的 90%

项目的效果

  • 默认展示高度:400px(第一个锚点)
  • 上拉后展开至:屏幕 50%(SheetSize.MEDIUM
  • 用户可以在两个高度之间拖拽切换

3.3 dragBar:拖拽把手

dragBar:false,// 不显示顶部的拖拽指示条

默认dragBar: true会在弹窗顶部显示一个灰色横条(拖拽指示器)。项目里关闭了,因为有title标题作为顶部元素,视觉上更简洁。

3.4 title:弹窗标题

title:{title:$r('app.string.gas_station')// 显示"加油站"}

在弹窗顶部显示标题文字,支持自定义样式:

title:{title:'加油站列表',subtitle:'附近4个加油站'// 可选副标题}

3.5 blurStyle:毛玻璃效果

blurStyle:BlurStyle.COMPONENT_THICK,

BlurStyle给弹窗背景加上毛玻璃模糊效果,透过弹窗能隐约看到地图:

BlurStyle模糊程度适用场景
THIN轻度模糊浅色背景
REGULAR常规模糊通用
THICK重度模糊深色背景
COMPONENT_THIN组件级轻度模糊推荐新项目用
COMPONENT_THICK组件级重度模糊本项目使用
NONE无模糊不需要毛玻璃

3.6 backgroundColor:背景颜色

backgroundColor:$r('app.color.bind_sheet_background'),// 白色

背景色和blurStyle叠加使用,创造半透明毛玻璃效果。

3.7 onWillDismiss:关闭前回调

onWillDismiss:((dismissSheetAction:DismissSheetAction)=>{// 在这里做关闭前的清理工作if(this.curMarker){this.imageScale=1;mapUtil.imageAnimation(this.curMarker,this.imageScale);}// 必须调用 dismiss() 确认关闭dismissSheetAction.dismiss();})

onWillDismiss在弹窗即将关闭时(用户下拉或点击遮罩)触发:

  1. 恢复当前选中 Marker 的大小
  2. 必须调用dismissSheetAction.dismiss()才会真正关闭弹窗(否则弹窗不会关闭)

这个设计允许你在"拦截"关闭时做一些操作,比如弹一个确认对话框:

onWillDismiss:((action:DismissSheetAction)=>{AlertDialog.show({message:'确定关闭吗?',confirm:{value:'确定',action:()=>{action.dismiss();}// 用户确认后才关闭}});})

四、bindBuilder:弹窗内容

@BuilderbindBuilder(){Column(){Scroll(){if(this.stationInfoList&&this.stationInfoList.length>0){List(){ForEach(this.stationInfoList,(station:StationData)=>{ListItem(){Row({space:Constants.SPACE_12}){this.stationInfoCard(station);}.width('100%');};},(station:StationData)=>{returnstation.id+station.name;});}.width('100%');}}.backgroundColor($r('app.color.start_window_background')).borderRadius(Constants.BORDER_RADIUS).margin({left:16,right:16}).opacity(Constants.ONE).scrollable(ScrollDirection.Vertical).edgeEffect(EdgeEffect.Fade)// 边缘渐隐效果.layoutWeight(Constants.ONE).align(Alignment.Top).height(Constants.MY_BUILDER_HEIGHT)// 300px.width('100%').scrollBar(BarState.Off);// 隐藏滚动条}.height(Constants.MY_BUILDER_COLUMN_HEIGHT);// 380px}

弹窗内容是一个可滚动的加油站列表,用Scroll包裹List实现滚动,edgeEffect(EdgeEffect.Fade)让列表边缘有渐隐效果。

五、弹窗的完整生命周期

isShow = false(弹窗隐藏) ↓ this.isShow = true(代码触发) 弹窗从底部滑入 ↓ 动画完成 弹窗显示(默认高度400px) ↓ 用户上拉 弹窗扩展(高度50%) ↓ 用户下拉或点遮罩 onWillDismiss 触发 ├─> 恢复 Marker 大小 └─> dismissSheetAction.dismiss() ↓ 弹窗从底部滑出 ↓ 动画完成 isShow = false(自动更新)

六、bindSheet vs 自定义弹窗

方式优点缺点
bindSheet原生动画流畅、支持拖拽、代码简洁样式自定义有限制
自定义(Stack+动画)完全自定义样式代码复杂、动画要自己写
Dialog居中弹窗,简单不适合底部抽屉样式

对于底部抽屉效果,强烈推荐用bindSheet,原生的手势交互(拖拽、弹性效果)是自定义组件很难复现的。

总结

bindSheet的核心配置:

  1. $$isShow:双向绑定的布尔变量,控制显示/隐藏
  2. detents:高度锚点数组,定义弹窗可停留的高度
  3. blurStyle:毛玻璃效果,COMPONENT_THICK效果最好
  4. onWillDismiss:关闭前回调,必须调用dismiss()才会真正关闭
  5. 弹窗内容是@Builder函数,任何 ArkUI 组件都可以放进去

下一篇讲GasStationPage 的完整实现解析——把整个地图页的代码从头到尾串一遍,让你看懂每一行的作用。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询