首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >HarmonyOS 开发实践 —— 基于手势绑定的常见问题处理

HarmonyOS 开发实践 —— 基于手势绑定的常见问题处理

原创
作者头像
小帅聊鸿蒙
发布2024-12-21 19:25:06
发布2024-12-21 19:25:06
4230
举报
文章被收录于专栏:鸿蒙开发笔记鸿蒙开发笔记

场景一:父子组件同时绑定手势的冲突处理

效果图

方案

在默认情况下,手势事件为非冒泡事件,当父子组件绑定相同的手势时,父子组件绑定的手势事件会发生竞争,最多只有一个组件的手势事件能够获得响应,默认子组件优先识别通过gesture绑定的手势。

  1. 当父组件使用priorityGesture绑定与子组件同类型的手势时,父组件优先识别通过priorityGesture绑定的手势,子组件的手势不会进行识别响应。
  2. 当父组件绑定了并行手势parallelGesture时,父子组件相同的手势事件都可以触发,实现类似冒泡效果(当前规格:当父组件和子组件同时绑定单击手势事件和双击手势事件时,父组件和子组件均只响应单击手势事件)。

核心代码

代码语言:ts
复制
build() {
  Column() {
    Column() {
      Text('TapGesture:' + this.priorityTestValue).fontSize(28)
        .gesture(
          TapGesture()
            .onAction(() => {
              this.priorityTestValue += '\n子组件响应'
            }))
    }
    .height(300)
    .width(250)
    .padding(20)
    .margin(20)
    .border({ width: 3 })
    // 设置为priorityGesture时,点击文本会忽略Text组件的TapGesture手势事件,优先识别父组件Column的TapGesture手势事件
    .priorityGesture(
      TapGesture()
        .onAction((event?: GestureEvent) => {
          this.priorityTestValue += '\n父组件响应'
        }), GestureMask.IgnoreInternal)
 
    Column() {
      Text('TapGesture:' + this.parallelTestValue).fontSize(28)
        .gesture(
          TapGesture()
            .onAction(() => {
              this.parallelTestValue += '\n子组件响应'
            }))
    }
    .height(300)
    .width(250)
    .padding(20)
    .margin(20)
    .border({ width: 3 })
    // 设置为parallelGesture时,点击文本会同时触发子组件Text与父组件Column的TapGesture手势事件
    .parallelGesture(
      TapGesture()
        .onAction((event?: GestureEvent) => {
          this.parallelTestValue += '\n父组件响应'
        }), GestureMask.Normal)
  }
}

场景二:手势实现自定义组件滑动离手后的惯性滑动效果

效果图

方案

通过GestureEvent中开放出来的的velocityX和velocityY分别对应当前手势的x轴方向速度和y轴方向速度,通过离手时的速度计算惯性滑动的距离,通过动画animateTo来模拟惯性滑动的效果。

核心代码

代码语言:ts
复制
.gesture(
  PanGesture(this.panOption)
    .onActionStart((event?: GestureEvent) => {
      console.info('Pan start')
    })
    .onActionUpdate((event?: GestureEvent) => {
      if (event) {
        this.vX = event.velocityX
        this.vY = event.velocityY
 
        this.offsetX = this.positionX + event.offsetX
        this.offsetY = this.positionY + event.offsetY
      }
    })
    .onActionEnd(() => {
      animateTo({
        duration: 1000,
        curve: Curve.EaseOut,
        iterations: 1,
        playMode: PlayMode.Normal,
        onFinish: () => {
          console.info('play end')
        }
      }, () => {
        // 滑动距离:s = Vo*t+(Vt-Vo)/t*t^2/2 = Vo*t+(Vt-Vo)*t/2 = Vo*t+Vt*t/2-Vo*t/2 = (Vo+Vt)*t/2
        // Vo = Vx  Vt = 0  当t=1时,
        this.offsetX = this.vX / 2
        this.offsetY = this.vY / 2
      })
    })
)

场景三:手势实现类似地图中搜索地址滑动效果

方案

使用bindSheet属性为组件绑定半模态页面,结合绑定并行手势事件parallelGesture,在手指上滑和下滑时分别进行手势的操作,修改半模态页面的高度值。

核心代码

  1. 手指上滑时:优先识别list组件自身滚动效果,当list滚动到临界值时,触发list组件的onReachEnd回调,在回调中修改自定义变量值;在并行手势parallelGesture的panGesture手势的onActionUpdate回调中,进行逻辑判断以及对半模态页面的高度进行动态赋值为原先高度加上手势偏移量。
代码语言:ts
复制
.onReachEnd(() => {
  this.reachEnd=true
  this.aaa=true
  this.reachStart=false
  console.log('onReachEnd', 'this.reachEnd:'+this.reachEnd,'this.reachStart:'+this.reachStart)
})

// list往上滑到头:识别手势,高度增加
if(this.reachEnd){
  animateTo({
    duration: 2000,
    curve: Curve.EaseOut,
    iterations: 1,
    playMode: PlayMode.Normal,
    onFinish: () => {
      console.info('play end')
    }
  }, () => {
    this.sheetHeight=this.setSheetHeight-event.offsetY
  })
  if(event.offsetY>0){
    this.reachEnd=false
    console.log('this.reachEnd', this.reachEnd)
  }
  console.log('offsetY 往上滑',event.offsetY,event.offsetY)
}
  1. 手指下滑时:优先识别List组件自身滚动效果,当List滚动到临界值时,触发List组件的onReachStart回调,在回调中修改自定义变量值;在并行手势parallelGesture的panGesture手势的onActionUpdate回调中,进行逻辑判断以及对半模态页面的高度进行动态赋值为原先高度减去手势偏移量。
代码语言:ts
复制
.onReachStart(() => {
  this.reachStart=true
  this.reachEnd=false
  console.log('onReachStart','this.reachEnd:'+this.reachEnd,'this.reachStart:'+this.reachStart)
})

// list往下滑到底,识别手势,高度减小
if(this.reachStart){
  animateTo({
    duration: 2000,
    curve: Curve.EaseOut,
    iterations: 1,
    playMode: PlayMode.Normal,
    onFinish: () => {
      console.info('play end')
    }
  }, () => {
    this.sheetHeight=this.setSheetHeight-event.offsetY
  })
  if(event.offsetY<0){
    this.reachStart=false
    console.log('this.reachEnd', this.reachStart)
  }
  console.log('offsetY 往下滑',event.offsetY,this.reachStart)
}

写在最后

如果你觉得这篇内容对你还蛮有帮助,我想邀请你帮我三个小忙:

  • 点赞,转发,有你们的 『点赞和评论』,才是我创造的动力;
  • 关注小编,同时可以期待后续文章ing🚀,不定期分享原创知识;
  • 想要获取更多完整鸿蒙最新学习知识点,可关注B站:码牛课堂;

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 场景一:父子组件同时绑定手势的冲突处理
    • 方案
  • 场景二:手势实现自定义组件滑动离手后的惯性滑动效果。
    • 方案
  • 场景三:手势实现类似地图中搜索地址滑动效果
    • 方案
  • 写在最后
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档