HarmonyOS鸿蒙Next中半模态(bindSheet)在最低档如何禁止下滑?
HarmonyOS鸿蒙Next中半模态(bindSheet)在最低档如何禁止下滑? 半模态(bindSheet)如何在最低档位的时候禁止下滑?我想做到向花瓣地图那种最小档位时无法下滑 现在使用半模态的效果是,可以继续往下滑然后在回弹到最小档位
3 回复
【解决方案】
可以使用滑动手势PanGesture事件来自定义半模态弹窗的滑动过程,实现最低挡位时禁止下拉回弹的效果。示例代码如下:
@Entry
@Component
struct SheetTransitionExample {
@State isShow: boolean = true;
@State @Watch('watchHeight') sheetHeight: number = 500;
@State @Watch('watchFlag') sheetFlag: SheetState = SheetState.MID;
@State changeValue: string = '';
@State submitValue: string = '';
controller: SearchController = new SearchController();
@State positionY: number = 500;
@Builder
myBuilder() {
Column() {
Search({ value: this.changeValue, placeholder: '搜地点、公交、地铁、城市', controller: this.controller })
.width('95%')
.height(40)
.backgroundColor('#F5F5F5')
.placeholderColor(Color.Grey)
.placeholderFont({ size: 14, weight: 400 })
.textFont({ size: 14, weight: 400 })
.onSubmit((value: string) => {
this.submitValue = value;
})
.onChange((value: string) => {
this.changeValue = value;
})
.margin(20);
// 使用if判断渲染刷新组件,半模态状态为TOP+MID时的组件
if (this.sheetFlag === SheetState.MID || this.sheetFlag === SheetState.TOP) {
Column() {
Row() {
Text('驾车');
Text('公交地铁');
Text('步行');
Text('打车');
Text('行程规划');
}
.justifyContent(FlexAlign.SpaceBetween)
.width('95%');
}
.justifyContent(FlexAlign.Center)
.height(50)
.width('90%')
.margin(20)
.borderRadius(8)
.borderWidth(1);
Column() {
Row() {
Text('常用地点');
Text('设置');
}
.justifyContent(FlexAlign.SpaceBetween)
.alignItems(VerticalAlign.Top)
.width('95%')
.margin(20);
Row() {
Column() {
Text('回家');
Text('点击设置');
};
Column() {
Text('去公司');
Text('点击设置');
};
}
.justifyContent(FlexAlign.SpaceBetween)
.width('95%')
.height(150);
}
.width('90%')
.borderRadius(8)
.borderWidth(1);
Text('test test test ')
.fontSize(40)
.margin(40);
}
// 使用if判断渲染刷新组件,半模态状态为TOP时的组件
if (this.sheetFlag === SheetState.TOP) {
Column() {
Image($r('app.media.background'))
.height(300)
.objectFit(ImageFit.Contain);
}
.transition(TransitionEffect.OPACITY.animation({ duration: 100 })); // 内容出现、消失的transition动效
}
}
.gesture(
// direction只涉及竖直方向上的移动,distance值设为1,使滑动更灵敏,避免造成事件错乱。
PanGesture({ direction: PanDirection.Vertical, distance: 1 })
.onActionStart(() => {
console.info('Pan start');
})
.onActionUpdate((event: GestureEvent) => {
// 手势事件偏移量Y,单位为vp,用于PanGesture手势触发场景,从上向下滑动offsetY为正,反之为负。
console.info(`onActionUpdate offsetY: ${event.offsetY}`);
// 当滑动时间没持续发生时,半模态高度只能在100-790之间移动
if (this.sheetHeight >= 100 && this.sheetHeight <= 790) {
// 当半模态高度为100,再往下滑动时直接返回
if (this.sheetHeight === 100 && event.offsetY > 0) {
return;
}
// 当半模态高度为790,再往上滑动时直接返回
if (this.sheetHeight === 790 && event.offsetY < 0) {
return;
}
// 手指持续滑动拖动半模态页面高度时,实时刷新半模态高度sheetHeight
this.sheetHeight = this.positionY + (-event.offsetY);
}
})
.onActionEnd((event: GestureEvent) => {
// 快速上滑时
if (event.offsetY < -10 && event.offsetY > -200) {
if (this.sheetFlag === SheetState.MID) {
this.getUIContext().animateTo({
duration: 300,
curve: Curve.Friction,
onFinish: () => {
this.sheetFlag = SheetState.TOP;
}
}, () => {
this.sheetHeight = 790;
});
} else if (this.sheetFlag === SheetState.BOTTOM) {
this.getUIContext().animateTo({
duration: 300,
curve: Curve.Friction,
onFinish: () => {
this.sheetFlag = SheetState.MID;
}
}, () => {
this.sheetHeight = 500;
});
}
}
// 快速上滑时
if (event.offsetY > 10 && event.offsetY < 200) {
if (this.sheetFlag === SheetState.TOP) {
this.getUIContext().animateTo({
duration: 300,
curve: Curve.Friction,
onFinish: () => {
this.sheetFlag = SheetState.MID;
}
}, () => {
this.sheetHeight = 500;
});
} else if (this.sheetFlag === SheetState.MID) {
this.getUIContext().animateTo({
duration: 300,
curve: Curve.Friction,
onFinish: () => {
this.sheetFlag = SheetState.BOTTOM;
}
}, () => {
this.sheetHeight = 100;
});
}
}
// 拖动手势结束时,半模态靠近哪个状态,就归到哪个状态
if (this.sheetHeight <= 790 && this.sheetHeight >= 650) {
this.getUIContext().animateTo({
duration: 300,
curve: Curve.Friction,
onFinish: () => {
this.sheetFlag = SheetState.TOP;
}
}, () => {
this.sheetHeight = 790;
});
} else if (this.sheetHeight < 650 && this.sheetHeight >= 300) {
this.getUIContext().animateTo({
duration: 300,
curve: Curve.Friction,
onFinish: () => {
this.sheetFlag = SheetState.MID;
}
}, () => {
this.sheetHeight = 500;
});
} else if (this.sheetHeight < 300 && this.sheetHeight >= 100) {
this.getUIContext().animateTo({
duration: 300,
curve: Curve.Friction,
onFinish: () => {
this.sheetFlag = SheetState.BOTTOM;
}
}, () => {
this.sheetHeight = 100;
});
}
// 上面onActionUpdate中半模态高度为最低或最高时,也能进入上、下滑判断,会导致高度为99或791,所以在onActionEnd中重新赋值,保障最高最低高度;
if (this.sheetHeight < 100) {
this.sheetHeight = 100;
this.sheetFlag = SheetState.BOTTOM;
} else if (this.sheetHeight > 790) {
this.sheetHeight = 790;
this.sheetFlag = SheetState.TOP;
}
// 记录这次滑动结束后的值,也是下次滑动开始的值
this.positionY = this.sheetHeight;
console.info('Pan end');
})
)
.width('100%')
.height('100%');
}
watchFlag() {
console.info(`watchFlag is: ${this.sheetFlag}`);
}
watchHeight() {
console.info(`watchHeight is: ${this.sheetHeight}`);
}
build() {
Column() {
Button('transition modal 1')
.onClick(() => {
this.isShow = true;
})
.fontSize(20)
.margin(10)
.bindSheet($$this.isShow, this.myBuilder(), {
height: this.sheetHeight,
// backgroundColor: Color.Green,
showClose: false,
onWillDismiss: ((DismissSheetAction: DismissSheetAction) => {
if (DismissSheetAction.reason == DismissReason.SLIDE_DOWN) {
//在最低档位下拉关闭时,拦截下拉关闭事件,不做处理=>业务上不用关闭半模态页面
}
}),
});
}
.justifyContent(FlexAlign.Center)
.width('100%')
.height('100%');
}
}
// 半模态状态:高中低
enum SheetState {
TOP,
MID,
BOTTOM,
}
更多关于HarmonyOS鸿蒙Next中半模态(bindSheet)在最低档如何禁止下滑?的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
在HarmonyOS Next中,要禁止半模态(bindSheet)在最低档下滑,可通过设置dragBar属性为false来实现。这将隐藏拖拽条并禁用下滑手势。
在HarmonyOS Next中,要实现在半模态(bindSheet)最低档位时禁止下滑,可以通过监听onWillDismiss事件并配合状态控制来实现。具体方法如下:
- 在Sheet组件的
onWillDismiss回调中判断当前是否处于最小档位,如果是则阻止关闭操作。 - 使用状态变量控制Sheet的可滑动行为,在最小档位时禁用滑动。
示例代码:
@State isMinPosition: boolean = false
build() {
Sheet(this.presenter)
.onWillDismiss(() => {
if (this.isMinPosition) {
// 阻止关闭
return false
}
return true
})
// ...其他配置
}
同时,需要在Sheet的onHeightChange回调中更新isMinPosition状态,通过判断当前高度是否等于最小高度来确定是否处于最小档位。
这种方式可以模拟花瓣地图的效果,在最小档位时阻止用户继续下滑,避免出现回弹现象。注意需要合理设置Sheet的最小高度和档位配置,确保交互逻辑符合预期。

