HarmonyOS 鸿蒙Next 如何在Swiper里实现视频播放器双指缩放并拖动?

发布于 1周前 作者 yibo5220 来自 鸿蒙OS

HarmonyOS 鸿蒙Next 如何在Swiper里实现视频播放器双指缩放并拖动?

组合手势顺序识别(PinchGesture + PanGesture(PanDirection.ALL)),捏合手势pinchGesture的onActionUpdate无法触发。

手势响应链如下:
捏合 + Pan的响应链是:PinchGesture onActionStartPanGesture onActionStartPanGesture onActionUpdatePanGesture onActionUpdatePanGesture onActionUpdatePanGesture onActionUpdatePanGesture onActionEnd

诉求:可以正常收到pinchGesture的onActionUpdate回调
 

2 回复

// src/main/ets/preview/Component/GalleryImage.ets

import display from '[@ohos](/user/ohos).display';

import {

  FingerDirection,

  HorizontalBoundary,

  ImageMeta,

  OnCompleteMsg,

  TouchPos,

  VerticalBoundary

} from '../interface';

[@Component](/user/Component)

export struct GalleryImage {

  [@Consume](/user/Consume)('pageInfos') pageInfos: NavPathStack;

  private MAX_SCALE = 3;

  private MIN_SCALE = 0.7;

  private DOUBLE_CLICK_SCALE = 1.5;

  [@Prop](/user/Prop) url: string = '';

  [@Prop](/user/Prop) index: number = 0;

  [@Prop](/user/Prop) showMenu: boolean = false;

  [@Link](/user/Link) isScaling: boolean;

  [@State](/user/State) downLoadEnable: boolean = false;

  [@State](/user/State) alt_name: string | Resource = $r('app.media.gallery_image_alt')

  [@State](/user/State) showLoading: boolean = false;

  [@State](/user/State) rotateAngle: number = 0;

  [@State](/user/State) isImageError: boolean = false;

  [@State](/user/State) touchFlag: number = 1;

  [@State](/user/State) temp: number = 0;

  [@State](/user/State) tempY: number = 0;

  private imageMeta: ImageMeta = {

    IMAGE_NAME: '',

    SUFFIX: '',

    IMAGE_WIDTH: 0,

    IMAGE_HEIGHT: 0,

    PAN_DIRECTION: PanDirection.All,

    MAX_SCALE_VALUE: this.MAX_SCALE

  };

  [@State](/user/State) scaleValue: number = 1;

  [@State](/user/State) pinchValue: number = 1;

  [@State](/user/State) pinchX: number | string = '50%';

  [@State](/user/State) pinchY: number | string = '50%';

  private panOption: PanGestureOptions = new PanGestureOptions({

    direction: this.imageMeta.PAN_DIRECTION,

    fingers: 1,

    distance: 2

  });

  [@State](/user/State) offsetX: number = 0;

  [@State](/user/State) offsetY: number = 0;

  private positionX: number = 0;

  private positionY: number = 0;

  private touchPos: TouchPos = {

    x: 0,

    y: 0

  };

  [@State](/user/State) fingerDirection: FingerDirection = FingerDirection.UNKNOWN;

  [@State](/user/State) xBoundary: HorizontalBoundary = HorizontalBoundary.MIDDLE;

  [@State](/user/State) yBoundary: VerticalBoundary = VerticalBoundary.MIDDLE;

  [@State](/user/State) leftBoundary: number = 0;

  [@State](/user/State) rightBoundary: number = 0;

  [@State](/user/State) topBoundary: number = 0;

  [@State](/user/State) bottomBoundary: number = 0;

  aboutToAppear(): void {

  }

  aboutToDisappear(): void {

  }

  build() {

    Column() {

      Video({ src: this.url, previewUri: $r('app.media.gallery_video_unmute_icon') })

        .width('100%')

        .height('100%')

        .objectFit(ImageFit.Contain)

        .autoPlay(true)

        .loop(true)

        .controls(false)

        .scale({

          x: this.scaleValue,

          y: this.scaleValue,

          z: 1,

          centerX: this.pinchX,

          centerY: this.pinchY

        })

        .translate({ x: this.offsetX, y: this.offsetY, z: 0 })

        .onImageGesture()

    }

    .width('100%')

    .height('100%')

    .justifyContent(FlexAlign.Center)

  }

  // 重置

  reset() {

    animateTo({

      duration: 400,

    }, () => {

      this.scaleValue = 1;

      this.pinchX = '50%';

      this.pinchY = '50%';

      this.pinchValue = this.scaleValue;

      this.offsetX = 0;

      this.offsetY = 0;

      this.positionX = 0;

      this.positionY = 0;

      this.xBoundary = 0;

      this.yBoundary = 0;

    })

  }

  [@Styles](/user/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();

          }),

        // 滑动手势

        SwipeGesture({ direction: SwipeDirection.Vertical })

          .onAction((event?: GestureEvent) => {

            console.log("SwipeGesture onAction --");

          }),

      )

    )

  }

  // 当捏合手势触发时,获取缩放比例,修改组件的缩放比例

  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 = event.pinchCenterY;

    }

  }

  getPinchY(pinchCenterY: number | string) {

    let pinchY = pinchCenterY;

    if (this.scaleValue > 1) {

      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.panOption.getDirection() === PanDirection.None) {

      console.log('pinch --reset ')

      this.reset();

      this.panOption.setDirection(PanDirection.All);

    }

  }

  // 当拖动手势触发时,获取偏移位置,并计算是否已到边界,不可拖出边界

  onPanGestureActionUpdate(event: GestureEvent) {

    if (this.scaleValue >= 1) {

      this.panOption.setDirection(PanDirection.None);

      return;

    }

    if (!event) {

      return;

    }

    this.panOption.setDirection(PanDirection.All);

    console.log('onPanGestureActionUpdate -- ')

    if (this.imageMeta.PAN_DIRECTION === PanDirection.All || this.imageMeta.PAN_DIRECTION === PanDirection.Vertical ||

      this.imageMeta.PAN_DIRECTION === PanDirection.Horizontal) {

      const NEWOFFSET_X = this.positionX + event.offsetX;

      this.offsetX = NEWOFFSET_X;

      console.log('x this.offsetX=' + this.offsetX)

      const NEWOFFSET_Y = this.positionY + event.offsetY;

      this.offsetY = NEWOFFSET_Y;

      console.log('y this.offsetY=' + this.offsetY)

    }

  }

  // 当拖动手势结束时,保存当前偏移位置

  onPanGestureActionEnd() {

    if (this.scaleValue < 1) {

      console.log('pan --reset ')

      this.reset();

    }

  }

}

在HarmonyOS鸿蒙Next系统中,若想在Swiper组件内实现视频播放器的双指缩放及拖动功能,通常需要对视频播放器控件进行自定义处理,并集成手势识别逻辑。以下是实现该功能的基本思路:

  1. 视频播放器控件:首先,确保你使用的视频播放器控件支持缩放功能。如果内置控件不支持,可以考虑使用第三方库或自行实现。

  2. 手势识别:使用HarmonyOS提供的手势识别API(如GestureDetector)来监听双指缩放及拖动手势。通过重写相关回调方法,获取手势的缩放比例和拖动距离。

  3. 缩放与拖动逻辑:在获取到手势信息后,根据缩放比例调整视频播放器的尺寸,同时根据拖动距离更新播放器的位置。这可能需要涉及到对播放器布局参数的动态修改。

  4. Swiper组件处理:确保Swiper组件能够正确传递手势事件到内部的视频播放器控件。这可能需要调整Swiper的触摸事件拦截策略。

  5. 测试与优化:在实现基本功能后,进行充分的测试,确保缩放与拖动操作流畅且无误。根据测试结果进行必要的优化。

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

回到顶部