一直想尝试下鸿蒙里面的动画开发,但是看了好几次官方文档里面的动画讲解,总有点似懂非懂的感觉,不是因为文档里面讲的太复杂,相反是讲的太简单了,实例也写的比较入门,基本都是通过一个按钮手动触发的动画,没有说如何直接启动一个动画,因为这里牵扯到一个动画变量值的改变时机,反正疑问还是蛮多的,最后在反复尝试了若干次之后,终于算是做出来了一个说得过去的动画效果,下面是整个动画的开发过程,希望对正处在初学阶段的鸿蒙开发者们有所帮助
绘制爱心
整个动画就是一个跳动并旋转的爱心,所以首先就需要在Canvas
中绘制出一个爱心,下面是对Canvas
的一些初始化操作
这里创建了一个自定义组件heart
,这个组件就用来绘制爱心,screenX
与screenY
分别表示画布的长与宽,这里还将画布的背景色设置成了透明,这样才能看起来是只有被绘制到的地方动起来,另外绘制爱心的地方这里设置成一个位于画布中间的一个正方形区域,所以这里还需要三个变量,分别表示这个区域的边长,最高位置与最低位置
startY
是最高位置的y坐标,endY
是最低位置的y坐标,shortSide
是区域的边长,然后在Canvas
里面给这几个变量赋值
下面是绘制爱心部分,整个爱心由两部分组成,每一部分分别都是一条贝塞尔曲线,而且是实心的贝塞尔曲线,绘制的代码如下
绘制本身不难,主要就是算好几个控制点的坐标就可以了,最后在入口组件里面调用heart
组件,一个红色的爱心就出来了,代码与效果图如下
爱心看起来不够立体,这里给爱心加点渐变色让它看起来立体些,方式就是在Canvas
中调用 createLinearGradient
生成一个CanvasGradient
对象,然后调用CanvasGradient
的 addColorStop
函数分别根据比例设置颜色,具体设置代码如下所示
现在就得到了一个内部渐变方向是从左上到右下的一个红色爱心了
动画部分
要让这个爱心跳动,最直接的办法就是让heart
组件不断更改它的上边距,从一个值到达另一个值,从而达到一个跳动的效果,那么首先我们先了解下用ArkTS如何去设置这么一个动画,这里就用到了animation
函数,它支持如下几个参数
- duration:动画的时长,默认值为1000毫秒
- tempo:动画播放的速度,速度与tempo的值成正比,默认值为1
- curve:动画曲线
- delay:延迟执行动画的时长
- iterations:动画播放的次数,默认值为1,表示i次,-1表示无限循环动画
- playMode :设置播放模式,默认值为
PlayMode.Normal
,表示播放完以后重新开始,PlayMode
还可以取值Reverse
表示反向播放,Alternate
表示正向反向交替播放,AlternateReverse
与Alternate
设置方向相反 - onFinish :表示动画结束以后的回调,当
iterations
为-1时候,不触发onFinish
这些都属于一个动画的属性,而能够让我们爱心跳动的方法就是给上边距设置一个@State
的变量,然后在onFinish
中不断去更改@State
的值,刷新heart
组件的上边距,这样爱心就跳起来了转换成代码就是下面这个样子
这里还增加了一个状态变量flag
,初始值为false
,而initSize
初始值为100,所以会在onFinish
中将initSize
变成20,flag
变成true,一个向上的动画就开启了,随着这个动画的结束,又触发onFinish
,initSize
变成200,flag
变成false
,就开启了一个向下的动画,这样反复的过程构成了爱心跳动的动画,我们看下效果
这颗爱心已经动起来了,但是离所谓的跳动还有点不一样,都知道由于重力作用的关系,物体向上运动是一个由快变慢的减速过程,而下落时则是一个由慢变快的加速过程,所以这里就需要在不同的过程里面设置不同的动画曲线curve
,当爱心向上运动时候,curve
设置为Curve.FastOutLinearIn
减速运动,当爱心下落时,curve
设置为Curve.LinearOutSlowIn
加速运动,更改后的代码如下所示
这样一来爱心的跳动就有了速率上的变化,就像真的在跳动一样,再看下效果
有了前车之鉴,再多加点动画效果就比较简单了,比如这里再增加一个旋转的动画,对于一个组件,要让它旋转的话可以使用rotate
函数,接收的也是一个@State
变量,并且在onFinish
的时候,改变这个旋转的变量值,就能完成旋转的动画了,代码如下
rotate
里面的参数angle
表示旋转的角度,当不指定方向参数时候,默认是绕着z轴旋转,也可以指定x,y,z参数,这样也会绕着指定轴旋转,这里我们就用默认的z轴旋转,每次动画结束让旋转的角度增加90度,来看下效果
一个完整的爱心跳动加旋转的动画就做好了,现在来给这个爱心加个影子,让跳动更加形象一些,实现一个影子其实就是在heart底下放一个灰色的组件,然后跟随着爱心跳动的动画,往上跳了影子就变小,往下掉了影子就变大,所以这就是一个影子组件的宽度和高度的变化动画,跟爱心的跳动一样,什么地方会变就创建什么样的状态变量,这里创建影子的宽高,还有控制宽高值改变的开关
然后就是创建影子了,影子就用一个Row
组件代替,设置一个灰色的背景,以及圆角,动画的属性基本跟跳动动画的属性一致,就是动画曲线没必要做速度变化的效果了,一个线性变化就好,影子的代码如下
这里还调用blur
方法给影子增加点模糊效果,来看下具体效果
到这里我们就完成了利用鸿蒙的属性动画来实现的一个跳动的爱心,但是这么个小动画看久了也腻,琢磨着再加点啥,在刚才的开发过程中我们利用属性动画更改了heart
组件的上边距以及底部影子的宽高,但貌似没有对heart
内部也就是Canvas
做改动,那么接下来我们就来动态更改下Canvas
的绘制颜色
更改爱心颜色
其实做这个部分的时候刚开始想的也是跟之前的动画一样,也用属性动画来做,但是后来发现怎么都改变不了Canvas
里面的颜色,想想也是,属性动画改变的也只能是Canvas
组件的属性,内部如何绘制其实不属于Canvas
的属性,当然改变不了,所以要换个思路,也就是每换一种颜色,就再创建一个Canvas
,那么Canvas
绘制的颜色就不一样了,所以这里就要使用另一个装饰器--@Builder,这个装饰器是干啥用的呢,官方文档里面解释是这样的
ArkUI还提供了一种更轻量的UI元素复用机制@Builder,@Builder所装饰的函数遵循build()函数语法规则,开发者可以将重复使用的UI元素抽象成一个方法,在build方法里调用。
说的还是蛮清楚的,将需要重复使用的ui元素抽取出来作为一个单独的方法,用@Builder
来修饰,在build
方法里面调用,也可以传递参数,那不就刚好用在我们这个场景吗,所以这里也将Canvas
抽到一个@Builder
的方法里面,代码如下
然后只需要在heart
组件里面原来Canvas
的地方换成调用paintJob
方法,最终达到的效果也是一样的
创建好了@Builder
方法以后,接下来就要做两件事情,一个是如何获取不同颜色,另一个是如何传入paintJob
方法里面,先创建需要用到的颜色
其中cur
为当前指向的数组下标,至于如何获取颜色,依然还是通过动画来获取,但是属性动画必须作用在一个组件上,所以这里建立一个空文案的Text
组件
只要将cur
作为文字大小作用在Text
的fontSize
属性上,就能触发onFinish
的回调,这里就是每秒钟cur
就会变换一次下标,然后就能通过下标cur
将colors
的颜色传到paintJob
方法里,这里又牵扯到一个问题,怎么传呢?@Builder
的函数提供了两种方式的传参,值传参跟引用传参,当需要传递的参数为状态变量时候,推荐使用引用传参,我们这边需要传递的参数为this.colors[this.cur]
,里面带有状态变量,所以使用引用传参方式,引用传参的格式如下
所以更改后的带有参数的paintJob
长这样
而调用paintJob
的地方,入参就要用一个大括号括起来,并且显式的将参数名写出来
最后在paintJob
里面需要使用参数的时候也不能直接拿来用,需要这样写$$.参数名
这样就成功的将颜色传递给了paintJob
函数,实现每一次创建Canvas
的时候使用不同的颜色绘制,来看下效果
总结
虽说用ArkTS实现了一个爱心跳动的动效,但是多多少少做的还不太顺手,里面有些细节我琢磨着应该还有更好的办法去处理,或者还得需要配合其他语法点一起才能做出更好的效果,反正再多做几个吧,从里面总结一下经验,争取每一次做的动效都能比前一次有所进步。