OpenHarmony 动画大全02-显式动画

2024-11-24 16:08:13
4次阅读
0个评论

OpenHarmony 动画大全02-显式动画

前言

上一篇文章我们介绍过属性动画animation的使用方法,那么本文就来学习和了解一下显示动画animateTo

animateTo

我们称之为显式动画,它本身是一个全局函数,通过调用函数的形式实现动画效果。显式动画animateTo和之前的属性动画

animation最大的区别在于 显式动画可以利用本身函数的特性实现多个显式动画连续调用,从而实现连贯性的动画。

基本语法

animateTo(value: AnimateParam, event: () => void): void

参数 类型 是否必填 描述
value AnimateParam 设置动画效果相关参数。
event () => void 指定动效的闭包函数

解释:

  1. AnimateParam 动画属性,在上一篇文章**《HarmonyNext动画大全01-属性动画》**内有详细介绍过

    名称 描述 示例
    duration 动画执行时间,单位毫秒 1000
    tempo 动画执行速度,默认是1,最小是0 1
    curve 动画曲线 比如匀速、先快后慢等 Curve.linear
    delay 延迟时间 单位毫秒 1000
    iterations 动画执行次数,-1 为无限 1
    playMode 动画播放模式 如播放两次时,每次都是从头开始播放 PlayMode.Normal
    onFinish 动画结束的回调函数

    其中,onFinish 是我们实现连续动画的关键

  2. event 指定动效的闭包函数

基本示例

1

@Entry
@Component
struct Index {
  @State
  scaleXY: number = 1

  build() {
    Column() {
      Button("点我就变大啦")
        .scale({ x: this.scaleXY, y: this.scaleXY })
        .onClick(() => {
          //   显式动画
          animateTo({
            // 1 指定动画参数
            duration: 1000
          }, () => {
            // 2 指定动效的闭包函数
            this.scaleXY = 2
          })
        })
    }
    .width("100%")
    .height("100%")
    .padding(40)
  }
}

代码解释

  1. 可以看到 animateTo就是一个全局函数,可以直接调用
  2. duration: 1000 表示动画参数,动画的持续时间为1s
  3. this.scaleXY = 2 放在 animateTo的第二个参数上,回调函数,也是在这里指定要具体执行的动画效果

至此,我们发现 显式动画 animateTo 和 之前的属性动画 animation 没有太大区别。 对的,因为他们两个最大的区别就在于 animateTo 可以比较方便实现连续多个动画效果

连续多个动画效果

如下图:

2

可以看到以上动画其实是有多个动画效果组合在一起的。如

  1. 左上角 -> 右上角
  2. 右上角 -> 右下角
  3. 右下角 -> 左下角
  4. 左下角 -> 左上角

我们思考:该如何实现呢?

答案是:onFinishonFinish 是动画参数中的一个属性,表示动画执行完毕。

onFinish

当动画执行完毕时,便会自动触发 onFinish里面的逻辑

3

@Entry
@Component
struct Index {
  @State
  x: number = 0
  @State
  y: number = 0

  build() {
    Column() {
      Row()
        .width(100)
        .height(100)
        .backgroundColor("#499C54")// tips: translate 表示设置位移
        .translate({
          x: this.x,
          y: this.y
        })
        .onClick(() => {
          animateTo({
            // 动画执行完毕触发
            onFinish: () => {
              AlertDialog.show({ message: "动画执行完毕" })
            }
          }, () => {
            this.x = 100
            this.y = 0
          })
        })
    }
    .width("100%")
    .height("100%")
    .alignItems(HorizontalAlign.Start)

  }
}

因此,当我们想要实现连续执行多个动画时,就不断往onFinish里面套娃即可

2

@Entry
@Component
struct Index {
  @State
  x: number = 0
  @State
  y: number = 0

  build() {
    Column() {
      Row()
        .width(100)
        .height(100)
        .backgroundColor("#499C54")
        .translate({
          x: this.x,
          y: this.y
        })
        .onClick(() => {
          // 1 左上角 -> 右上角
          animateTo({
            onFinish: () => {
              // 2 右上角 -> 右下角
              animateTo({
                onFinish: () => {
                  // 3 右下角 -> 左下角
                  animateTo({
                    onFinish: () => {
                      // 4 左下角 -> 左上角
                      animateTo({}, () => {
                        this.x = 0
                        this.y = 0
                      })
                    }
                  }, () => {
                    this.x = 0
                    this.y = 100
                  })
                }
              }, () => {
                this.x = 100
                this.y = 100
              })
            }
          }, () => {
            this.x = 100
            this.y = 0
          })
        })
    }
    .width("100%")
    .height("100%")
    .alignItems(HorizontalAlign.Start)

  }
}

以上这个代码,就可以实现连续动画了。

回调函数地狱


但是,这个代码结构,妈妈看到了很难不夸你写得好

image-20240816011629339

以上结构已经形成了一个回调函数地狱了,小伙伴们~😂

解决回调函数地狱

有开发经验的小伙们应该可以马上想到解决方法

  1. promise
  2. asyncawait

对的,回调函数地狱可以靠这两个老哥来解决。

先拿 animateToPromise 做一个封装

const animateToPromise = (option: AnimateParam, fn: Function) => {
  const promise: Promise<undefined> = new Promise((resolve: Function) => {
    option.onFinish = () => {
      resolve()
    }
    animateTo(option, () => {
      fn()
    })
  })
  return promise
}

最后再来看解决后的版本

  Row() {

  }
  .width(100)
  .height(100)
  .backgroundColor("#499C54")
  .translate({ x: this.x, y: this.y })
  .onClick(async () => {
    // 1 左上角 -> 右上角
    await animateToPromise({}, () => {
      this.x = 100
      this.y = 0
    })
    // 2 右上角 -> 右下角
    await animateToPromise({}, () => {
      this.x = 100
      this.y = 100
    })
    // 3 右下角 -> 左下角
    await animateToPromise({}, () => {
      this.x = 0
      this.y = 100
    })
    // 4 左下角 -> 左上角
    await animateToPromise({}, () => {
      this.x = 0
      this.y = 0
    })
  })

可以看到,封装后的代码,要简洁不少

image-20240816012146982

小结

  1. animateTo 适合用在连续多个动画效果上
  2. animateTo 可以搭配promiseasyncawait 解决回调地狱的问题
  3. 由于篇幅问题,这里没有直接介绍promise和async。

作者

作者:万少

链接:https://www.nutpi.net/

來源:坚果派 著作权归作者所有。

商业转载请联系作者获得授权,非商业转载请注明出处。

收藏00

登录 后评论。没有帐号? 注册 一个。