HarmonyOS 鸿蒙Next 手势拖拽时和Swiper组件滑动发生冲突如何解决

发布于 1周前 作者 zlyuanteng 最后一次编辑是 5天前 来自 鸿蒙OS

HarmonyOS 鸿蒙Next 手势拖拽时和Swiper组件滑动发生冲突如何解决

【问题现象】

用Swiper实现图片的预览、缩放和切换。

期待效果:既可以对图片进行预览、缩放、拖拽,又可以切换不同图片进行预览。

实际效果:只能对图片进行预览、缩放、拖拽,无法切换不同的图片进行预览。

问题代码如下:

// 单手指动作,移动图片PanGesture({ fingers: 1 })
  .onActionUpdate((event: GestureEvent) => {
    if (this.imageScaleInfo.scaleValue === this.imageScaleInfo.defaultScaleValue) {
      // 默认大小下不允许移动
      return true;
    }
    // 修改坐标轴位置
    this.imageOffsetInfo.currentX = this.imageOffsetInfo.lastX + event.offsetX;
    this.imageOffsetInfo.currentY = this.imageOffsetInfo.lastY + event.offsetY;
    return false;
  })
  .onActionEnd((event: GestureEvent) => {
    // 设置图片大小值
    this.imageOffsetInfo.stash();
  })

【背景知识】

Swiper官方文档链接:滑块视图容器,提供子组件滑动轮播显示的能力。

TapGesture官方文档链接:支持单击、双击和多次点击事件的识别。

【定位思路】

单手指事件会对图片进行位置的移动,跟Swiper组件滑动发生冲突。因此,只需要把单手指的事件取消掉,就可以实现Swiper组件滑动来切换图片。

【解决方案】

根据以上分析,解决方案如下:

(1)取消掉Swiper组件下的缩放效果,即把关于手势事件的问题代码都删除掉,只保留原始的切换图片效果。在点击图片时,进入一个新的图片预览页面,在预览页面添加手势事件的代码,进行图片的缩放和拖拽操作。

(2)当预览结束后,返回到可以滑动切换图片的页面。

图片缩放及预览解决方案如下:

1. 双击切换图片大小

代码示例如下:

TapGesture({ count: 2 })
  .onAction(() => {
    let fn: Function;
    // 已经是放大状态下,双击缩小
    if (this.imageScaleInfo.scaleValue > this.imageScaleInfo.defaultScaleValue) {
      fn = () => {
        this.isEnableSwipe = true;
        // 修改图片大小到初始值
        this.imageScaleInfo.reset();
        // 修改图片偏移量到初始值
        this.imageOffsetInfo.reset();
        this.matrix = matrix4.identity().copy();
      };
    } else {
      // 已经是缩小状态,双击放大
      fn = () => {
        this.isEnableSwipe = false;
        // 根据图片初始大小和屏幕的大小计算缩放比例的值
        const ratio: number = this.calcFitScaleRatio(this.imageDefaultSize, windowSizeManager.get());
        // 通过计算出来的缩放比例来对图片进行放大
        this.imageScaleInfo.scaleValue = ratio;
        // 修改图片偏移量到初始值
        this.imageOffsetInfo.reset();
        this.matrix = matrix4.identity().scale({
          x: ratio,
          y: ratio,
        }).copy();
        this.imageScaleInfo.stash();
      }
    }
    runWithAnimation(fn);
  })

2. 双指捏合缩放图片

代码示例如下:

PinchGesture({ fingers: 2, distance: 1 })
  .onActionUpdate((event: GestureEvent) => {
    // 根据双指捏合事件捕捉到的缩放值,进行图片尺寸的重新计算
    this.imageScaleInfo.scaleValue = this.imageScaleInfo.lastValue * event.scale;
    // 缩放时不允许大于最大缩放因子+额外缩放因子,不允许小于默认大小-额外缩放因子,额外缩放因子用于提升用户体验
    if (this.imageScaleInfo.scaleValue > this.imageScaleInfo.maxScaleValue *
      (1 + this.imageScaleInfo.extraScaleValue)
    ) {
      this.imageScaleInfo.scaleValue = this.imageScaleInfo.maxScaleValue *
        (1 + this.imageScaleInfo.extraScaleValue);
    }
    if (this.imageScaleInfo.scaleValue < this.imageScaleInfo.defaultScaleValue *
      (1 - this.imageScaleInfo.extraScaleValue)) {
      this.imageScaleInfo.scaleValue = this.imageScaleInfo.defaultScaleValue *
        (1 - this.imageScaleInfo.extraScaleValue);
    }
    // matrix默认缩放中心为组件中心
    this.matrix = matrix4.identity().scale({
      x: this.imageScaleInfo.scaleValue,
      y: this.imageScaleInfo.scaleValue,
    }).copy();
    console.debug(this.imageScaleInfo.toString());
  })
    // 缩放事件结束,对特殊情况进行判断后,根据计算出来的新的尺寸值,对图片的重新渲染
  .onActionEnd((event: GestureEvent) => {
    /**
     * 当小于默认大小时,恢复为默认大小
     */
    if (this.imageScaleInfo.scaleValue < this.imageScaleInfo.defaultScaleValue) {
      runWithAnimation(() => {
        // 修改图片大小到初始值
        this.imageScaleInfo.reset();
        // 修改图片偏移量到初始值
        this.imageOffsetInfo.reset();
        this.matrix = matrix4.identity().copy();
      })
    }
    // 当大于最大缩放因子时,恢复到最大
    if (this.imageScaleInfo.scaleValue > this.imageScaleInfo.maxScaleValue) {
      runWithAnimation(() => {
        this.imageScaleInfo.scaleValue = this.imageScaleInfo.maxScaleValue;
        this.matrix = matrix4.identity()
          .scale({
            x: this.imageScaleInfo.maxScaleValue,
            y: this.imageScaleInfo.maxScaleValue
          });
      })
    }
    // 根据新计算出来的图片大小值来重新渲染图片
    this.imageScaleInfo.stash();
  })

3. 单手指拖拽图片至指定位置预览

代码示例如下:

PanGesture({ fingers: 1 })
  .onActionUpdate((event: GestureEvent) => {
    console.info("event", JSON.stringify(event))
    // 根据事件捕捉到的坐标轴值来修改图片的坐标,实现拖动图片的效果
    this.imageOffsetInfo.currentX = this.imageOffsetInfo.lastX + event.offsetX;
    this.imageOffsetInfo.currentY = this.imageOffsetInfo.lastY + event.offsetY;
    return false;
  })
  .onActionEnd((event: GestureEvent) => {
    // 根据新的坐标轴来渲染图片的位置
    this.imageOffsetInfo.stash();
  })
1 回复

在HarmonyOS鸿蒙Next中,手势拖拽与Swiper组件滑动发生冲突的问题,通常涉及到手势事件的分发与消费机制。以下是一些专业解决方案:

  1. 事件拦截:确保Swiper组件正确拦截并处理滑动事件。子组件的拖拽手势应设置为在特定条件下才响应,比如当Swiper不处于滑动状态时。这可以通过自定义组件或修改事件监听逻辑来实现。
  2. 手势优先级:在组件树中,调整手势识别器的优先级,确保Swiper的滑动手势优先级高于子组件的拖拽手势。这通常涉及修改手势识别器的配置或重写事件处理逻辑。
  3. 状态同步:使用全局或局部状态管理来同步Swiper和子组件的状态。当Swiper处于滑动状态时,临时禁用或忽略子组件的拖拽手势。
  4. 条件判断:在子组件的拖拽事件处理函数中,加入条件判断逻辑。如果检测到Swiper正在滑动,则不处理拖拽事件。

这些解决方案可以有效地解决手势拖拽与Swiper组件滑动之间的冲突,提高用户界面的交互体验。如果在实际应用中遇到复杂情况,可能需要根据具体场景进行定制化处理。

如果问题依旧没法解决请联系官网客服,官网地址是:https://www.itying.com/category-93-b0.html

回到顶部