HarmonyOS 鸿蒙Next中根据ID从一点到另一点到动画设计

HarmonyOS 鸿蒙Next中根据ID从一点到另一点到动画设计 工具类util:

import { Animator as animator, AnimatorResult, AnimatorOptions, Offset, componentUtils, UIContext } from '@kit.ArkUI'

export class AnimateMoveById {
  constructor(fromPosId: string, toPosId: string, uiContext: UIContext, currentPos: Offset,
    animatorOptions?: AnimatorOptions, onFinish?: () => void, onCancel?: ()=> void) {
    this.fromPosId = fromPosId
    this.toPosId = toPosId
    this.uiContext = uiContext
    this.currentPos = currentPos
    if (animatorOptions) {
      this.controller = animator.create(animatorOptions)
    } else {
      this.controller = animator.create({
        // 建议使用 this.getUIContext.creatAnimator()接口
        duration: 3000,
        easing: "ease",
        delay: 0,
        fill: "forwards",
        direction: "normal",
        iterations: 1,
        begin: 0.0,
        end: 100.0
      })
    }
    if(onFinish){
      this.controller.onFinish = onFinish
    }
    if(onCancel){
      this.controller.onCancel = onCancel
    }
  }

  controller: AnimatorResult | undefined = undefined
  fromPosId: string = ''
  toPosId: string = ''
  fromPos: Offset | null = null
  toPos: Offset | null = null
  currentPos: Offset = { x: 0, y: 0 }
  uiContext: UIContext = new UIContext()

  play(): AnimateMoveById {
    this.fromPos = componentUtils.getRectangleById(this.fromPosId).windowOffset
    this.toPos = componentUtils.getRectangleById(this.toPosId).windowOffset
    this.currentPos!!.x = this.uiContext.px2vp(this.fromPos.x)
    this.currentPos!!.y = this.uiContext.px2vp(this.fromPos.y)
    let ox = this.currentPos!!.x
    let oy = this.currentPos!!.y
    if (this.controller) {
      this.controller.onFrame = (value: number) => {
        if (this.currentPos) {
          this.currentPos!!.x =
            this.uiContext.px2vp((this.toPos!!.x - this.fromPos!!.x) * value / 100.0) + ox
          this.currentPos!!.y =
            this.uiContext.px2vp((this.toPos!!.y - this.fromPos!!.y) * value / 100.0) + oy
        }
      }
      this.controller.play()
    }

    return this
  }
}

使用时:

  let options: AnimatorOptions = {
    duration: 6000,
    easing: "ease",
    delay: 0,
    fill: "forwards",
    direction: "normal",
    iterations: 1,
    begin: 0.0,
    end: 100.0
  }
  let a = new AnimateMoveById('0', '1', this.getUIContext(), this.currentPos!!, options, () => {
    toast.show('动画结束了!')
  }, () => {
    toast.show('取消动画回调')
  })
  this.animateText = '这是一个动画'
  // a.controller!!.onCancel = () => {
  //   toast.show('取消动画回调')
  // }
  // if(a.controller){
  //   a.controller.onFinish = () =>{
  //     toast.show('动画结束了!')
  //   }
  // }
  a.play()
  // setTimeout(() => {
  //   a.controller?.cancel()
  // }, 2000)
})

同时需要给要定位动画的首位和末位加上.id()


更多关于HarmonyOS 鸿蒙Next中根据ID从一点到另一点到动画设计的实战教程也可以访问 https://www.itying.com/category-93-b0.html

2 回复

在HarmonyOS Next中,可通过animateTo方法实现基于ID的组件间动画。使用globalThis或组件上下文获取目标ID的引用,配置位置、平移等属性变化。通过animation属性定义动画曲线与时长,例如使用animateTo执行位移。具体实现需结合ArkUI声明式语法与状态管理驱动动画过程。

更多关于HarmonyOS 鸿蒙Next中根据ID从一点到另一点到动画设计的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在HarmonyOS Next中,通过组件ID实现动画移动是可行的,但代码存在几个关键问题需要修正:

  1. 构造函数中的currentPos参数类型应为Offset引用而非值传递,否则无法实时更新位置。建议改为:
constructor(..., currentPos: Ref<Offset>, ...)
  1. px2vp单位转换逻辑错误,应该先计算物理像素差值再转换:
this.currentPos.x = ox + this.uiContext.px2vp((this.toPos.x - this.fromPos.x) * value / 100)
this.currentPos.y = oy + this.uiContext.px2vp((this.toPos.y - this.fromPos.y) * value / 100)
  1. 建议使用getUIContext().createAnimator()替代直接调用animator.create,确保动画与当前UI上下文关联

  2. 需要确保源和目标组件已通过.id()方法设置有效ID,且组件已完成布局(建议在onReady后执行动画)

修正后的play()方法应包含位置获取的null检查,避免运行时错误。

回到顶部