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

效果图

方案

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

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

核心代码

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来模拟惯性滑动的效果。

核心代码

.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回调中,进行逻辑判断以及对半模态页面的高度进行动态赋值为原先高度加上手势偏移量。

    .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回调中,进行逻辑判断以及对半模态页面的高度进行动态赋值为原先高度减去手势偏移量。

    .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)
}

HarmonyOS码上奇行
5k 声望2.5k 粉丝