HarmonyOS鸿蒙实战( Beta6版)手势的图片预览与缩放

159 篇文章 0 订阅
159 篇文章 0 订阅

场景一:对图片进行放大、缩小、拖拽移动,且放大过程中也可同时进行拖拽操作

方案

1、使用组合手势GestureGroup,同时绑定捏合手势PinchGesture和滑动手势PanGesture,设置组合手势识别模式为并行识别模式:Parallel,并行识别组合手势中注册的手势将同时进行识别,直到所有手势识别结束,并行识别手势组合中的手势进行识别时互不影响。

2、在对图片进行双指捏合时,优先触发绑定的PinchGesture手势,对图片进行缩放操作;当滑动拖拽图片时,识别绑定的PanGesture手势,对图片进行拖拽移动。

核心代码

1、绑定组合手势GestureGroup,设置为并行识别模式,添加捏合手势PinchGesture和滑动手势PanGesture。

@Styles
onImageGesture(){
  .gesture(
    GestureGroup(GestureMode.Parallel,
      // 双指捏合手势
      PinchGesture({ fingers: 2, distance: 0.1 })
        .onActionUpdate((event: GestureEvent) => {
          this.onPinchGestureActionUpdate(event);
        })
        .onActionEnd(() => {
          this.onPinchGestureActionEnd();
        }),
      // 拖动手势
      PanGesture(this.panOption)
        .onActionUpdate((event?: GestureEvent) => {
          this.onPanGestureActionUpdate(event);
        })
        .onActionEnd(() => {
          this.onPanGestureActionEnd();
        })
    )
  )
}

2、在捏合手势的onActionUpdate和onActionEnd回调中修改scale参数,进行图片缩放处理。

// 当捏合手势触发时,可以通过回调函数获取缩放比例,从而修改组件的缩放比例
onPinchGestureActionUpdate(event: GestureEvent) {
  const SCALE_VALUE = this.pinchValue * event.scale;
  if (SCALE_VALUE <= this.imageMeta.MAX_SCALE_VALUE && SCALE_VALUE >= this.MIN_SCALE) {
    this.scaleValue = SCALE_VALUE;
    this.pinchX = event.pinchCenterX;
    this.pinchY = this.getPinchY(event.pinchCenterY);
    if (this.scaleValue > 1) {
      this.offsetX = 0;
    }
  }
}

getPinchY(pinchCenterY: number | string) {
  let pinchY = pinchCenterY;
  if (this.scaleValue > 1) {
    // 当为横图时,在留白处放大,图片位置不居中,手动计算pinchY,并移动Y轴中心点,即offsetY
    if (this.imageMeta.IMAGE_WIDTH >= this.imageMeta.IMAGE_HEIGHT) {
      const SCREEN_HEIGHT = px2vp(display.getDefaultDisplaySync().height);
      const MIN_PINCH_Y = SCREEN_HEIGHT / 2 - this.imageMeta.IMAGE_HEIGHT / 2;
      const MAX_PINCH_Y = SCREEN_HEIGHT / 2 + this.imageMeta.IMAGE_HEIGHT / 2;
      const MIDDLE_PINCH_Y = SCREEN_HEIGHT / 2;
      if (pinchY < MIN_PINCH_Y) {
        pinchY = MIN_PINCH_Y;
      }
      if (pinchY > MAX_PINCH_Y) {
        pinchY = MAX_PINCH_Y;
      }
      if (pinchY < MIDDLE_PINCH_Y && typeof this.pinchY === 'number') {
        this.offsetY = (Number(pinchY) - MIDDLE_PINCH_Y) * (this.scaleValue - 1);
      }
      if (pinchY > MIDDLE_PINCH_Y && typeof this.pinchY === 'number') {
        this.offsetY = (Number(pinchY) - MIDDLE_PINCH_Y) * (this.scaleValue - 1);
      }
    }
  }
  return pinchY;
}

// 当捏合手势结束时,计算当前的isScaling
// 如果缩放比例小于1,弹簧效果重置成原比例
onPinchGestureActionEnd() {
  this.pinchValue = this.scaleValue;
  if (this.pinchValue > 1) {
    this.scaleEnable();
  } else {
    this.scaleUnEnable();
    if (this.pinchValue < 1) {
      this.reset();
    }
  }
}

场景二:图片在放大的情况下也可切换到后一张图或者前一张图

方案

1、在panGesture手势的onActionUpdate回调中获取偏移位置,计算图片放大后分别往左或者往右拖动时是否到达边界,记录向左或向右边界的状态。

2、在onTouch事件中识别手指滑动方向,并判断边界是翻页还是拖动,方向为左右且到达边界,执行scaleUnEnable方法,将panGesture手势方向置为none,执行翻页;反之执行滑动手势,不翻页。

核心代码

1、在PanGesture手势的onActionUpDate回调中获取偏移位置,计算拖拽过程中左右两边分别是否已到边界。

// 当拖动手势触发时,可以通过回调函数获取偏移位置,并计算是否已到边界,不可拖出边界
onPanGestureActionUpdate(event: GestureEvent) {
  if (!event || this.scaleValue <= 1) {
    return;
  }
  let boundaryOffset: BoundaryOffset = {
    left: 0,
    right: 0,
    top: 0,
    bottom: 0
  };
  this.xBoundary = HorizontalBoundary.MIDDLE;
  this.yBoundary = VerticalBoundary.MIDDLE;

  const CENTER_X_RELATIVE = typeof this.pinchX === 'number' ? this.pinchX / this.imageMeta.IMAGE_WIDTH : 0.5;
  boundaryOffset.left = this.imageMeta.IMAGE_WIDTH * (this.scaleValue - 1) * CENTER_X_RELATIVE;
  boundaryOffset.right = -this.imageMeta.IMAGE_WIDTH * (this.scaleValue - 1) * (1 - CENTER_X_RELATIVE);
  const NEWOFFSET_X = this.positionX + event.offsetX;
  // 更新x轴偏移位置
  if (NEWOFFSET_X <= boundaryOffset.left && newOffsetX >= boundaryOffset.right) {
    // 在中间
    this.offsetX = NEWOFFSET_X;
  } else {
    // 在边界
    if (this.fingerDirection === FingerDirection.LEFT && this.offsetX !== boundaryOffset.right) {
      this.offsetX = boundaryOffset.right;
    }
    if (this.fingerDirection === FingerDirection.RIGHT && this.offsetX !== boundaryOffset.left) {
      this.offsetX = boundaryOffset.left;
    }
  }
  // 在左边界
  if (NEWOFFSET_X >= boundaryOffset.left) {
    this.xBoundary = HorizontalBoundary.LEFT;
  }
  // 在右边界
  if (NEWOFFSET_X <= boundaryOffset.right) {
    this.xBoundary = HorizontalBoundary.RIGHT;
  }
  if (this.imageMeta.PAN_DIRECTION === PanDirection.All || this.imageMeta.PAN_DIRECTION === PanDirection.Vertical||this.imageMeta.PAN_DIRECTION === PanDirection.Horizontal) {
    // 更新y轴偏移量
    const NEWOFFSET_Y = this.positionY + event.offsetY;
    this.offsetY = NEWOFFSET_Y;
  }
}

2、通过绑定onTouch事件,在滑动的过程中根据手指方向和是否到达边界通过isPageChangeOnBoundary方法判断后分别执行scaleEnable和scaleUnEnable方法进行翻页或者拖动处理。

// 识别手指滑动方向,并判断边界是翻页还是拖动
@Styles
onImageTouch(){
  .onTouch((event: TouchEvent) => {
    if (this.scaleValue > 1) {
      if (event.type === TouchType.Down) {
        this.touchPos.x = event.touches[0].x;
        this.touchPos.y = event.touches[0].y;
      }
      if (event.type === TouchType.Move) {
        this.fingerDirection = getMoveFingerDirection(this.touchPos, event, this.fingerDirection);
        if (!isPageChangeOnBoundary(this.fingerDirection, this.xBoundary)) {
          if (!this.isScaling) {
            this.touchFlag = 1;
            this.scaleEnable();
            this.xBoundary = HorizontalBoundary.MIDDLE;
            this.temp = this.offsetX;
            this.tempY = this.offsetY;
          }
        }
      }
      if (event.type === TouchType.Up) {
        if (this.touchFlag == 1) {
          this.onPanGestureActionEnd();
        }
        this.touchFlag = 0;
        this.temp = 0;
        this.tempY = 0;
        if (isPageChangeOnBoundary(this.fingerDirection, this.xBoundary) || this.scaleValue === 1) {
          this.scaleUnEnable();
        } else {
          this.scaleEnable();
        }
      }
    }
  })
}

// 拖动,不翻页
scaleEnable() {
  if (this.isScaling) {
    return;
  }
  this.panOption.setDirection(this.imageMeta.PAN_DIRECTION);
  this.isScaling = true;
}

// 不能拖动,翻页
scaleUnEnable() {
  if (!this.isScaling) {
    return;
  }
  this.panOption.setDirection(PanDirection.None);
  this.isScaling = false;
}

3、在isPageChangeOnBoundary 方法中根据传入的手指滑动方向和拖动到达的边界方向来判断返回,之后再分别调用不同场景下的方法处理逻辑,进行翻页或者拖动。

// 在边界进行翻页
export const isPageChangeOnBoundary = (fingerDirection: FingerDirection, xBoundary: HorizontalBoundary) => {
  return (fingerDirection === FingerDirection.LEFT && xBoundary === HorizontalBoundary.RIGHT ||
    fingerDirection === FingerDirection.RIGHT && xBoundary === HorizontalBoundary.LEFT);
}

最后

小编在之前的鸿蒙系统扫盲中,有很多朋友给我留言,不同的角度的问了一些问题,我明显感觉到一点,那就是许多人参与鸿蒙开发,但是又不知道从哪里下手,因为资料太多,太杂,教授的人也多,无从选择。有很多小伙伴不知道学习哪些鸿蒙开发技术?不知道需要重点掌握哪些鸿蒙应用开发知识点?而且学习时频繁踩坑,最终浪费大量时间。所以有一份实用的鸿蒙(HarmonyOS NEXT)文档用来跟着学习是非常有必要的。 

为了确保高效学习,建议规划清晰的学习路线,涵盖以下关键阶段:

点击 →【纯血版鸿蒙全套最新学习文档】希望这一份鸿蒙学习文档能够给大家带来帮助~


 鸿蒙(HarmonyOS NEXT)最新学习路线

该路线图包含基础技能、就业必备技能、多媒体技术、六大电商APP、进阶高级技能、实战就业级设备开发,不仅补充了华为官网未涉及的解决方案

路线图适合人群:

IT开发人员:想要拓展职业边界
零基础小白:鸿蒙爱好者,希望从0到1学习,增加一项技能。
技术提升/进阶跳槽:发展瓶颈期,提升职场竞争力,快速掌握鸿蒙技术

2.学习视频+学习PDF文档

HarmonyOS Next 最新全套视频教程 (鸿蒙语法ArkTS、TypeScript、ArkUI教程……)

​​

 纯血版鸿蒙全套学习文档(面试、文档、全套视频等)

                   

​​​​鸿蒙APP开发必备

​​

总结

点击【纯血版鸿蒙全套最新学习文档】

总的来说,华为鸿蒙不再兼容安卓,对程序员来说是一个挑战,也是一个机会。只有积极应对变化,不断学习和提升自己,才能在这个变革的时代中立于不败之地。

 

  • 18
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值