【HarmonyOS】头像圆形裁剪功能之手势放大缩小,平移,双击缩放控制(三)

【HarmonyOS】头像裁剪之手势放大缩小,平移,双击缩放控制(三)

一、DEMO效果图:
在这里插入图片描述
在这里插入图片描述

二、开发思路:
使用矩阵变换控制图片的放大缩小和平移形态。

通过监听点击手势TapGesture,缩放手势PinchGesture,拖动手势PanGesture进行手势操作的功能实现。

通过对矩阵变换参数mMatrix的赋值,将矩阵变换参数赋值给image控件。实现手势操作和图片操作的同步。

在这里插入图片描述
该参数拥有四维坐标,只需要通过手势操作调整四个参数即可实现。通过.transform(this.mMatrix)赋值给image控件。

通过image的.onComplete(this.onLoadImgComplete)函数回调,获取图片控件的宽高和内容宽高等参数。以此为基准,手势操作调整的都是这些值。

三、DEMO示例代码:

import router from '@ohos.router';
import { CropMgr, ImageInfo } from '../manager/CropMgr';
import { image } from '@kit.ImageKit';
import Matrix4 from '@ohos.matrix4';
import FS from '@ohos.file.fs';

export class LoadResult {
  width: number = 0;
  height: number = 0;
  componentWidth: number = 0;
  componentHeight: number = 0;
  loadingStatus: number = 0;
  contentWidth: number = 0;
  contentHeight: number = 0;
  contentOffsetX: number = 0;
  contentOffsetY: number = 0;
}





export struct CropPage {
  private TAG: string = "CropPage";

  private mRenderingContextSettings: RenderingContextSettings = new RenderingContextSettings(true);
  private mCanvasRenderingContext2D: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.mRenderingContextSettings);

  // 加载图片
   mImg: PixelMap | undefined = undefined;
  // 图片矩阵变换参数
   mMatrix: object = Matrix4.identity()
    .translate({ x: 0, y: 0 })
    .scale({ x: 1, y: 1});

   mImageInfo: ImageInfo = new ImageInfo();

  private tempScale = 1;
  private startOffsetX: number = 0;
  private startOffsetY: number = 0;

  aboutToAppear(): void {
    console.log(this.TAG, "aboutToAppear start");
    let temp = CropMgr.Ins().mSourceImg;
    console.log(this.TAG, "aboutToAppear temp: " + JSON.stringify(temp));
    this.mImg = temp;
    console.log(this.TAG, "aboutToAppear end");
  }

  private getImgInfo(){
    return this.mImageInfo;
  }

  onClickCancel = ()=>{
    router.back();
  }

  onClickConfirm = async ()=>{
    if(!this.mImg){
      console.error(this.TAG, " onClickConfirm mImg error null !");
      return;
    }

    // 存当前裁剪的图
	// ...
    router.back();
  }

  /**
   * 复制图片
   * @param pixel
   * @returns
   */
  async copyPixelMap(pixel: PixelMap): Promise<PixelMap> {
    const info: image.ImageInfo = await pixel.getImageInfo();
    const buffer: ArrayBuffer = new ArrayBuffer(pixel.getPixelBytesNumber());
    await pixel.readPixelsToBuffer(buffer);
    const opts: image.InitializationOptions = {
      editable: true,
      pixelFormat: image.PixelMapFormat.RGBA_8888,
      size: { height: info.size.height, width: info.size.width }
    };
    return image.createPixelMap(buffer, opts);
  }

  /**
   * 图片加载回调
   */
  private onLoadImgComplete = (msg: LoadResult) => {
    this.getImgInfo().loadResult = msg;
    this.checkImageScale();
  }

  /**
   * 绘制画布中的取景框
   */
  private onCanvasReady = ()=>{
    if(!this.mCanvasRenderingContext2D){
      console.error(this.TAG, "onCanvasReady error mCanvasRenderingContext2D null !");
      return;
    }
    let cr = this.mCanvasRenderingContext2D;
    // 画布颜色
    cr.fillStyle = '#AA000000';
    let height = cr.height;
    let width = cr.width;
    cr.fillRect(0, 0, width, height);

    // 圆形的中心点
    let centerX = width / 2;
    let centerY = height / 2;
    // 圆形半径
    let radius = Math.min(width, height) / 2 - px2vp(100);
    cr.globalCompositeOperation = 'destination-out'
    cr.fillStyle = 'white'
    cr.beginPath();
    cr.arc(centerX, centerY, radius, 0, 2 * Math.PI);
    cr.fill();

    cr.globalCompositeOperation = 'source-over';
    cr.strokeStyle = '#FFFFFF';
    cr.beginPath();
    cr.arc(centerX, centerY, radius, 0, 2 * Math.PI);
    cr.closePath();

    cr.lineWidth = 1;
    cr.stroke();
  }

  build() {
    RelativeContainer() {
      // 黑色底图
      Row().width("100%").height("100%").backgroundColor(Color.Black)

      // 用户图
      Image(this.mImg)
        .objectFit(ImageFit.Contain)
        .width('100%')
        .height('100%')
        .transform(this.mMatrix)
        .alignRules({
          center: { anchor: '__container__', align: VerticalAlign.Center },
          middle: { anchor: '__container__', align: HorizontalAlign.Center }
        })
        .onComplete(this.onLoadImgComplete)

      // 取景框
      Canvas(this.mCanvasRenderingContext2D)
        .width('100%')
        .height('100%')
        .alignRules({
          center: { anchor: '__container__', align: VerticalAlign.Center },
          middle: { anchor: '__container__', align: HorizontalAlign.Center }
        })
        .backgroundColor(Color.Transparent)
        .onReady(this.onCanvasReady)
        .clip(true)
        .backgroundColor("#00000080")

      Row(){
        Button("取消")
          .size({
            width: px2vp(450),
            height: px2vp(200)
          })
          .onClick(this.onClickCancel)

        Blank()

        Button("确定")
          .size({
            width: px2vp(450),
            height: px2vp(200)
          })
          .onClick(this.onClickConfirm)
      }
      .width("100%")
      .height(px2vp(200))
      .margin({ bottom: px2vp(500) })
      .alignRules({
        center: { anchor: '__container__', align: VerticalAlign.Bottom },
        middle: { anchor: '__container__', align: HorizontalAlign.Center }
      })
      .justifyContent(FlexAlign.Center)

    }
    .width("100%").height("100%")
    .priorityGesture(
      // 点击手势
      TapGesture({
        // 点击次数
        count: 2,
        // 一个手指
        fingers: 1
      }).onAction((event: GestureEvent)=>{
        console.log(this.TAG, "TapGesture onAction start");
        if(!event){
          return;
        }
        if(this.getImgInfo().scale != 1){
          this.getImgInfo().scale = 1;
          this.getImgInfo().offsetX = 0;
          this.getImgInfo().offsetY = 0;
          this.mMatrix = Matrix4.identity()
            .translate({
              x: this.getImgInfo().offsetX,
              y: this.getImgInfo().offsetY
            })
            .scale({
              x: this.getImgInfo().scale,
              y: this.getImgInfo().scale
            })
        }else{
          this.getImgInfo().scale = 2;
          this.mMatrix = Matrix4.identity()
            .translate({
              x: this.getImgInfo().offsetX,
              y: this.getImgInfo().offsetY
            })
            .scale({
              x: this.getImgInfo().scale,
              y: this.getImgInfo().scale
            })
        }

        console.log(this.TAG, "TapGesture onAction end");
      })
    )
    .gesture(GestureGroup(
      GestureMode.Parallel,
      // 缩放手势
      PinchGesture({
        // 两指缩放
        fingers: 2
      })
        .onActionStart(()=>{
          console.log(this.TAG, "PinchGesture onActionStart");
          this.tempScale = this.getImgInfo().scale;
        })
        .onActionUpdate((event)=>{
          console.log(this.TAG, "PinchGesture onActionUpdate" + JSON.stringify(event));
          if(event){
            this.getImgInfo().scale = this.tempScale * event.scale;
            this.mMatrix = Matrix4.identity()
              .translate({
                x: this.getImgInfo().offsetX,
                y: this.getImgInfo().offsetY
              })
              .scale({
                x: this.getImgInfo().scale,
                y: this.getImgInfo().scale
              })
          }
        })
        .onActionEnd(()=>{
          console.log(this.TAG, "PinchGesture onActionEnd");
 
        })
      ,
      // 拖动手势
      PanGesture()
        .onActionStart(()=>{
          console.log(this.TAG, "PanGesture onActionStart");
          this.startOffsetX = this.getImgInfo().offsetX;
          this.startOffsetY = this.getImgInfo().offsetY;
      })
        .onActionUpdate((event)=>{
          console.log(this.TAG, "PanGesture onActionUpdate" + JSON.stringify(event));
          if(event){
            let distanceX: number = this.startOffsetX + vp2px(event.offsetX) / this.getImgInfo().scale;
            let distanceY: number = this.startOffsetY + vp2px(event.offsetY) / this.getImgInfo().scale;
            this.getImgInfo().offsetX = distanceX;
            this.getImgInfo().offsetY = distanceY;
            this.mMatrix = Matrix4.identity()
              .translate({
                x: this.getImgInfo().offsetX,
                y: this.getImgInfo().offsetY
              })
              .scale({
                x: this.getImgInfo().scale,
                y: this.getImgInfo().scale
              })
          }
        })
        .onActionEnd(()=>{
          console.log(this.TAG, "PanGesture onActionEnd");
        })
    ))
  }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值