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

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

手势响应链如下:

捏合 + Pan的响应链是:PinchGesture onActionStartPanGesture onActionStartPanGesture onActionUpdatePanGesture onActionUpdatePanGesture onActionUpdatePanGesture onActionUpdatePanGesture onActionEnd

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

场景描述:视频播放器除了常规的长按、点击、上下左右拖动手势,还需要可以对视频画面进行捏合缩放以及拖动查看局部画面。

HarmonyOS
3天前
浏览
收藏 0
回答 1
待解决
回答 1
按赞同
/
按时间
FengTianYa

示例如下:

// src/main/ets/preview/Component/GalleryImage.ets
import display from '@ohos.display';
import {
  FingerDirection,
  HorizontalBoundary,
  ImageMeta,
  OnCompleteMsg,
  TouchPos,
  VerticalBoundary
} from '../interface';

@Component
export struct GalleryImage {
  @Consume('pageInfos') pageInfos: NavPathStack;
  private MAX_SCALE = 3;
  private MIN_SCALE = 0.7;
  private DOUBLE_CLICK_SCALE = 1.5;
  @Prop url: string = '';
  @Prop index: number = 0;
  @Prop showMenu: boolean = false;
  @Link isScaling: boolean;
  @State downLoadEnable: boolean = false;
  @State alt_name: string | Resource = $r('app.media.gallery_image_alt')
  @State showLoading: boolean = false;
  @State rotateAngle: number = 0;
  @State isImageError: boolean = false;
  @State touchFlag: number = 1;
  @State temp: number = 0;
  @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 scaleValue: number = 1;
  @State pinchValue: number = 1;
  @State pinchX: number | string = '50%';
  @State pinchY: number | string = '50%';
  private panOption: PanGestureOptions = new PanGestureOptions({
    direction: this.imageMeta.PAN_DIRECTION,
    fingers: 1,
    distance: 2
  });
  @State offsetX: number = 0;
  @State offsetY: number = 0;
  private positionX: number = 0;
  private positionY: number = 0;
  private touchPos: TouchPos = {
    x: 0,
    y: 0
  };
  @State fingerDirection: FingerDirection = FingerDirection.UNKNOWN;
  @State xBoundary: HorizontalBoundary = HorizontalBoundary.MIDDLE;
  @State yBoundary: VerticalBoundary = VerticalBoundary.MIDDLE;
  @State leftBoundary: number = 0;
  @State rightBoundary: number = 0;
  @State topBoundary: number = 0;
  @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
  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();
    }
  }
}
分享
微博
QQ
微信
回复
3天前
相关问题
使用AVPlayer实现视频播放器
1331浏览 • 1回复 待解决
HarmonyOS 视频播放器问题
35浏览 • 1回复 待解决
HarmonyOS 视频播放器如何旋转屏幕
17浏览 • 1回复 待解决
HarmonyOS 点播视频播放器选型咨询
285浏览 • 1回复 待解决
Image组件如何实现手势放大
2428浏览 • 1回复 待解决