文章目录
- 前言
- 方案对比表
- 详细实现
- 水平拖拽
- 垂直拖拽
- 完整代码
- 优劣分析
- 实际案例
- 侧滑删除
- 下拉刷新
- 写在最后
前言
上篇文章讲了自由拖拽——方块可以往任何方向移动。但实际场景中,很多时候我们需要限制拖拽方向。比如:
- 音量滑块只能水平拖动
- 下拉刷新只能垂直拖动
- 侧滑删除只能水平拖动
PanGesture的direction参数就是用来限制拖拽方向的。
方案对比表
PanDirection提供了以下枚举值:
| 值 | 说明 | 适用场景 |
|---|---|---|
All | 所有方向 | 自由拖拽 |
Horizontal | 仅水平 | 滑块、轮播 |
Vertical | 仅垂直 | 下拉、列表排序 |
Left | 仅向左 | 右滑删除 |
Right | 仅向右 | 左滑展开 |
|Up| 仅向上 | 上滑关闭 |
|Down| 仅向下 | 下拉刷新 |
详细实现
水平拖拽
@StatehOffsetX:number=0@StatehPosX:number=0Stack(){Row(){Column(){Text('← →').fontSize(18).fontColor('#FFFFFF')}.width(70).height(50).backgroundColor('#4D96FF').borderRadius(12).justifyContent(FlexAlign.Center).alignItems(HorizontalAlign.Center).offset({x:this.hOffsetX,y:0}).gesture(PanGesture({direction:PanDirection.Horizontal}).onActionUpdate((event:GestureEvent)=>{this.hOffsetX=this.hPosX+event.offsetX}).onActionEnd(()=>{this.hPosX=this.hOffsetX}))}}.width('100%').height(60).backgroundColor('#F8F8F8').borderRadius(10)关键点:
direction: PanDirection.Horizontal— 只响应水平方向的拖拽.offset({ x: this.hOffsetX, y: 0 })— Y 轴固定为 0,只在 X 轴移动onActionUpdate只使用event.offsetX,忽略event.offsetY
用户上下拖动手指时,方块不会有反应——只有左右拖动才会移动。
垂直拖拽
@StatevOffsetY:number=0@StatevPosY:number=0Stack(){Column(){Column(){Text('↑ ↓').fontSize(18).fontColor('#FFFFFF')}.width(70).height(50).backgroundColor('#6BCB77').borderRadius(12).justifyContent(FlexAlign.Center).alignItems(HorizontalAlign.Center).offset({x:0,y:this.vOffsetY}).gesture(PanGesture({direction:PanDirection.Vertical}).onActionUpdate((event:GestureEvent)=>{this.vOffsetY=this.vPosY+event.offsetY}).onActionEnd(()=>{this.vPosY=this.vOffsetY}))}}.width('100%').height(60).backgroundColor('#F8F8F8').borderRadius(10)垂直拖拽跟水平拖拽的写法完全对称——direction改成Vertical,.offset()的 X 固定为 0,使用event.offsetY。
完整代码
@Entry@Componentstruct PanGestureDirection{@StatehOffsetX:number=0@StatehPosX:number=0@StatevOffsetY:number=0@StatevPosY:number=0build(){Column(){Column(){Text('拖拽方向限制').fontSize(16).fontWeight(FontWeight.Bold).margin({bottom:16})// 水平拖拽Text('水平拖拽(Horizontal)').fontSize(14).fontColor('#666666').margin({bottom:8})Stack(){Row(){Column(){Text('← →').fontSize(18).fontColor('#FFFFFF')}.width(70).height(50).backgroundColor('#4D96FF').borderRadius(12).justifyContent(FlexAlign.Center).alignItems(HorizontalAlign.Center).offset({x:this.hOffsetX,y:0}).gesture(PanGesture({direction:PanDirection.Horizontal}).onActionUpdate((event:GestureEvent)=>{this.hOffsetX=this.hPosX+event.offsetX}).onActionEnd(()=>{this.hPosX=this.hOffsetX}))}}.width('100%').height(60).backgroundColor('#F8F8F8').borderRadius(10)// 垂直拖拽Text('垂直拖拽(Vertical)').fontSize(14).fontColor('#666666').margin({bottom:8})Stack(){Column(){Column(){Text('↑ ↓').fontSize(18).fontColor('#FFFFFF')}.width(70).height(50).backgroundColor('#6BCB77').borderRadius(12).justifyContent(FlexAlign.Center).alignItems(HorizontalAlign.Center).offset({x:0,y:this.vOffsetY}).gesture(PanGesture({direction:PanDirection.Vertical}).onActionUpdate((event:GestureEvent)=>{this.vOffsetY=this.vPosY+event.offsetY}).onActionEnd(()=>{this.vPosY=this.vOffsetY}))}}.width('100%').height(60).backgroundColor('#F8F8F8').borderRadius(10)}.width('100%').padding(24).backgroundColor('#FFFFFF').borderRadius(12)}.width('100%').height('100%').backgroundColor('#F5F6FA').padding(16)}}优劣分析
限制方向的优势:
- 防止误操作——用户无意中的斜向滑动不会干扰目标方向的拖拽
- 交互语义更清晰——水平就是水平,垂直就是垂直
- 简化偏移计算——只需要处理一个轴的数据
限制方向的劣势:
- 系统判断方向需要一定的拖拽距离,可能导致初始响应有延迟
- 用户手指的实际滑动轨迹很少有绝对水平或垂直的,系统需要做方向判定
实际案例
侧滑删除
.gesture(PanGesture({direction:PanDirection.Left}).onActionUpdate((event:GestureEvent)=>{this.slideOffset=Math.max(-80,event.offsetX)}).onActionEnd(()=>{if(this.slideOffset<-40){this.slideOffset=-80// 展开删除按钮}else{this.slideOffset=0// 收回}}))下拉刷新
.gesture(PanGesture({direction:PanDirection.Down}).onActionUpdate((event:GestureEvent)=>{this.pullDistance=Math.min(100,event.offsetY)}).onActionEnd(()=>{if(this.pullDistance>60){this.refreshData()}this.pullDistance=0}))写在最后
PanDirection让拖拽手势变得精确可控。水平拖拽配水平方向的限制,垂直拖拽配垂直方向的限制——方向明确,交互才清晰。
在实际项目中,90% 的拖拽场景都需要限制方向。自由拖拽虽然酷,但大多数时候用户不需要(也不想要)一个可以到处乱拖的组件。