HarmonyNext动画大全02-显式动画
前言
上一篇文章我们介绍过属性动画animation
的使用方法,那么本文就来学习和了解一下显示动画animateTo
animateTo
我们称之为显式动画,它本身是一个全局函数,通过调用函数的形式实现动画效果。显式动画animateTo
和之前的属性动画
animation
最大的区别在于 显式动画可以利用本身函数的特性实现多个显式动画连续调用,从而实现连贯性的动画。
基本语法
animateTo(value: AnimateParam, event: () => void): void
参数 | 类型 | 是否必填 | 描述 |
value | AnimateParam | 是 | 设置动画效果相关参数。 |
event | () => void | 是 | 指定动效的闭包函数 |
解释:
AnimateParam
动画属性,在上一篇文章**《HarmonyNext动画大全01-属性动画》**内有详细介绍过
名称 | 描述 | 示例 |
duration | 动画执行时间,单位毫秒 | 1000 |
tempo | 动画执行速度,默认是1,最小是0 | 1 |
curve | 动画曲线 比如匀速、先快后慢等 | Curve.linear |
delay | 延迟时间 单位毫秒 | 1000 |
iterations | 动画执行次数,-1 为无限 | 1 |
playMode | 动画播放模式 如播放两次时,每次都是从头开始播放 | PlayMode.Normal |
onFinish | 动画结束的回调函数 |
- 其中,onFinish 是我们实现连续动画的关键
event
指定动效的闭包函数
基本示例
@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) } }
代码解释:
- 可以看到
animateTo
就是一个全局函数,可以直接调用 duration: 1000
表示动画参数,动画的持续时间为1sthis.scaleXY = 2
放在animateTo
的第二个参数上,回调函数,也是在这里指定要具体执行的动画效果
至此,我们发现 显式动画 animateTo
和 之前的属性动画 animation
没有太大区别。 对的,因为他们两个最大的区别就在于 animateTo
可以比较方便实现连续多个动画效果。
连续多个动画效果
如下图:
可以看到以上动画其实是有多个动画效果组合在一起的。如
- 左上角 -> 右上角
- 右上角 -> 右下角
- 右下角 -> 左下角
- 左下角 -> 左上角
我们思考:该如何实现呢?
答案是:onFinish。 onFinish
是动画参数中的一个属性,表示动画执行完毕。
onFinish
当动画执行完毕时,便会自动触发 onFinish
里面的逻辑
@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
里面套娃即可
@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) } }
以上这个代码,就可以实现连续动画了。
回调函数地狱
但是,这个代码结构,妈妈看到了很难不夸你写得好
以上结构已经形成了一个回调函数地狱了,小伙伴们~😂
解决回调函数地狱
有开发经验的小伙们应该可以马上想到解决方法
promise
async
和await
对的,回调函数地狱可以靠这两个老哥来解决。
先拿 animateTo
和 Promise
做一个封装
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 }) })
可以看到,封装后的代码,要简洁不少
小结
animateTo
适合用在连续多个动画效果上animateTo
可以搭配promise
和async
、await
解决回调地狱的问题- 由于篇幅问题,这里没有直接介绍promise和async。