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。