HarmonyOS 通过拖动手势来控制圆形半径实现圆形区域变化,存在半径突变、不连贯的情况

页面demo:

https://clouddrive.huawei.com/p/9724406abd6f1f5b2dd4f2acf7f9d59e

目前半径为某些值时拖动过程中会存在半径突变、不连贯的情况,如何修改

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

请参考如下修改:

export class Rect {
  minX: number
  maxX: number
  minY: number
  maxY: number

  constructor(minX: number, maxX: number, minY: number, maxY: number) {
    this.minX = minX
    this.maxX = maxX
    this.minY = minY
    this.maxY = maxY
  }

  toString() {
    return `[Rect] minX: ${this.minX}, maxX: ${this.maxX}, minY: ${this.minY}, maxY: ${this.maxY}`
  }

  include(x: number, y: number): boolean {
    return x >= this.minX && x <= this.maxX && y >= this.minY && y <= this.maxY
  }
}

const TAG = "ManualExpandArea"
const DEFAULT_CIRCLE_RADIUS = 72
const MIN_CIRCLE_RADIUS = 13
const CIRCLE_LINE_WIDTH = 2

const EXPAND_WIDGET_SIZE = 32

const GESTURE_ACTION_EXPAND = 1 // 手势拖动缩放
const GESTURE_ACTION_MOVE = 2 // 手势拖动移动

let offsetX = 0
let offsetY = 0
let flag = true
let offsetR = 0
const change = 1

@Component
@Entry
struct Index {
  build() {
    Stack({ alignContent: Alignment.Center }) {
      ManualExpandArea()
    }.width('100%').height('100%').backgroundColor(Color.Black)
  }
}

@Component
export struct ManualExpandArea {
  @State @Watch("onCircleRadiusChanged") private circleRadius: number = DEFAULT_CIRCLE_RADIUS
  @State private componentSize: number = this.getComponentSize()
  @State private gestureAction: number = GESTURE_ACTION_EXPAND
  @State private moveOffsetX: number = 0
  @State private moveOffsetY: number = 0
  @State private positionX: number = 0
  @State private positionY: number = 0
  private settings: RenderingContextSettings = new RenderingContextSettings(true)
  private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
  private originCircleRadius: number = 0

  onCircleRadiusChanged() {
    this.componentSize = this.getComponentSize()
  }

  build() {
    Stack({ alignContent: Alignment.TopStart }) {
      Canvas(this.context)
        .width('100%')
        .height('100%')
        .onReady(() => {
          this.invalidate();
        })
      Image($r('app.media.startIcon'))
        .width(EXPAND_WIDGET_SIZE)
        .height(EXPAND_WIDGET_SIZE)
        .margin({ left: this.getExpandMargin(), top: this.getExpandMargin() })
      Text(this.circleRadius.toString())
        .fontColor(Color.White)
    }
    .width(this.componentSize)
    .height(this.componentSize)
    .translate({ x: this.moveOffsetX, y: this.moveOffsetY, z: 0 })
    .gesture(PanGesture({
      fingers: 1, // 仅响应单指
    }).onActionStart((event) => {
      let localX: number = event.fingerList[0].localX
      let localY: number = event.fingerList[0].localY
      let inExpandRect = this.judgeInExpandRect(localX, localY)
      console.log(TAG, `x: ${localX}, y: ${localY}, inExpand: ${inExpandRect}`)
      if (inExpandRect) {
        this.originCircleRadius = this.circleRadius
        this.gestureAction = GESTURE_ACTION_EXPAND
      } else {
        this.gestureAction = GESTURE_ACTION_MOVE
      }
    }).onActionUpdate((event) => {
      if (this.gestureAction == GESTURE_ACTION_EXPAND) {
        // TODO
        console.log(TAG, "▲offsetX:" + (event.offsetX - offsetX))
        console.log(TAG, "▲offsetY:" + (event.offsetY - offsetY))
        let offsetRadius = this.calOffsetRadius(event.offsetX - offsetX, event.offsetY - offsetY)
        // let offsetRadius = this.calOffsetRadius(event.offsetX, event.offsetY)
        offsetX = event.offsetX
        offsetY = event.offsetY
        console.error(TAG, "▲Radius: " + (offsetRadius - offsetR))
        offsetR = offsetRadius
        console.log(TAG, "radius: " + (this.circleRadius + offsetRadius))
        this.circleRadius = Math.max(this.circleRadius + offsetRadius, MIN_CIRCLE_RADIUS)
        // console.log(TAG, "radius: " + (this.originCircleRadius + offsetRadius))
        // this.circleRadius = Math.max(this.originCircleRadius + offsetRadius, MIN_CIRCLE_RADIUS)
        // this.invalidate()
      } else if (this.gestureAction == GESTURE_ACTION_MOVE) {
        this.moveOffsetX = this.positionX + event.offsetX
        this.moveOffsetY = this.positionY + event.offsetY
      }
    }).onActionEnd(() => {
      this.positionX = this.moveOffsetX
      this.positionY = this.moveOffsetY
      offsetX = 0
      offsetY = 0
    }))
  }

  invalidate() {
    this.context.reset()
    this.drawFullCircle()
  }

  drawFullCircle() {
    this.context.beginPath()
    this.context.lineWidth = CIRCLE_LINE_WIDTH
    this.context.strokeStyle = '#ffffff'
    let circleCenter = this.circleRadius + CIRCLE_LINE_WIDTH
    this.context.arc(circleCenter, circleCenter, this.circleRadius, 0, 6.28);
    this.context.stroke()
  }

  getComponentSize(): number {
    return (this.circleRadius + CIRCLE_LINE_WIDTH) * 2
  }

  // Expand 组件位于圆形右下角 45°
  getExpandMargin(): number {
    return CIRCLE_LINE_WIDTH + this.circleRadius + this.circleRadius / Math.SQRT2 - EXPAND_WIDGET_SIZE / 2
  }

  // 通过手势移动计算半径差值
  calOffsetRadius(offsetX: number, offsetY: number): number {
    let tmpRet: number = 0
    if (offsetX > 0) {
      tmpRet += offsetX * offsetX
    } else {
      tmpRet -= offsetX * offsetX
    }
    if (offsetY > 0) {
      tmpRet += offsetY * offsetY
    } else {
      tmpRet -= offsetY * offsetY
    }
    if (tmpRet > 0) {
      console.log(TAG, "Math.sqrt(tmpRet): " + Math.sqrt(tmpRet))
      return Math.sqrt(tmpRet)
    } else {
      console.log(TAG, "-Math.sqrt(-tmpRet): " + -Math.sqrt(-tmpRet))
      return -Math.sqrt(-tmpRet)
    }
  }

  judgeInExpandRect(localX: number, localY: number): boolean {
    let expandCenter = this.getExpandMargin() + EXPAND_WIDGET_SIZE / 2
    let expandRect = new Rect(
      expandCenter - EXPAND_WIDGET_SIZE / 2, expandCenter + EXPAND_WIDGET_SIZE / 2,
      expandCenter - EXPAND_WIDGET_SIZE / 2, expandCenter + EXPAND_WIDGET_SIZE / 2
    )
    console.log(TAG, `expand rect: ${expandRect.toString()}`)
    return expandRect.include(localX, localY)
  }
}
分享
微博
QQ
微信
回复
1天前
相关问题
HarmonyOS 拖动手势距离单位是什么
39浏览 • 1回复 待解决
HarmonyOS 如何较好实现圆形头像
90浏览 • 1回复 待解决
HarmonyOS 怎么设置圆形边框
35浏览 • 1回复 待解决
HarmonyOS 如何设置图片为圆形
24浏览 • 1回复 待解决
鸿蒙 如何实现一个渐变圆形图片;
12647浏览 • 2回复 已解决
HarmonyOS image如何把图片裁剪成圆形
66浏览 • 1回复 待解决