ArkTS实现一个跳动的爱心

一直想尝试下鸿蒙里面的动画开发,但是看了好几次官方文档里面的动画讲解,总有点似懂非懂的感觉,不是因为文档里面讲的太复杂,相反是讲的太简单了,实例也写的比较入门,基本都是通过一个按钮手动触发的动画,没有说如何直接启动一个动画,因为这里牵扯到一个动画变量值的改变时机,反正疑问还是蛮多的,最后在反复尝试了若干次之后,终于算是做出来了一个说得过去的动画效果,下面是整个动画的开发过程,希望对正处在初学阶段的鸿蒙开发者们有所帮助

绘制爱心

整个动画就是一个跳动并旋转的爱心,所以首先就需要在Canvas中绘制出一个爱心,下面是对Canvas的一些初始化操作

这里创建了一个自定义组件heart,这个组件就用来绘制爱心,screenXscreenY分别表示画布的长与宽,这里还将画布的背景色设置成了透明,这样才能看起来是只有被绘制到的地方动起来,另外绘制爱心的地方这里设置成一个位于画布中间的一个正方形区域,所以这里还需要三个变量,分别表示这个区域的边长,最高位置与最低位置

startY是最高位置的y坐标,endY是最低位置的y坐标,shortSide是区域的边长,然后在Canvas里面给这几个变量赋值

下面是绘制爱心部分,整个爱心由两部分组成,每一部分分别都是一条贝塞尔曲线,而且是实心的贝塞尔曲线,绘制的代码如下

绘制本身不难,主要就是算好几个控制点的坐标就可以了,最后在入口组件里面调用heart组件,一个红色的爱心就出来了,代码与效果图如下

爱心看起来不够立体,这里给爱心加点渐变色让它看起来立体些,方式就是在Canvas中调用 createLinearGradient生成一个CanvasGradient对象,然后调用CanvasGradientaddColorStop函数分别根据比例设置颜色,具体设置代码如下所示

现在就得到了一个内部渐变方向是从左上到右下的一个红色爱心了

动画部分

要让这个爱心跳动,最直接的办法就是让heart组件不断更改它的上边距,从一个值到达另一个值,从而达到一个跳动的效果,那么首先我们先了解下用ArkTS如何去设置这么一个动画,这里就用到了animation函数,它支持如下几个参数

  • duration:动画的时长,默认值为1000毫秒
  • tempo:动画播放的速度,速度与tempo的值成正比,默认值为1
  • curve:动画曲线
  • delay:延迟执行动画的时长
  • iterations:动画播放的次数,默认值为1,表示i次,-1表示无限循环动画
  • playMode :设置播放模式,默认值为PlayMode.Normal,表示播放完以后重新开始,PlayMode还可以取值Reverse表示反向播放,Alternate表示正向反向交替播放,AlternateReverseAlternate设置方向相反
  • 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作为文字大小作用在TextfontSize属性上,就能触发onFinish的回调,这里就是每秒钟cur就会变换一次下标,然后就能通过下标curcolors的颜色传到paintJob方法里,这里又牵扯到一个问题,怎么传呢?@Builder的函数提供了两种方式的传参,值传参跟引用传参,当需要传递的参数为状态变量时候,推荐使用引用传参,我们这边需要传递的参数为this.colors[this.cur],里面带有状态变量,所以使用引用传参方式,引用传参的格式如下

所以更改后的带有参数的paintJob长这样

而调用paintJob的地方,入参就要用一个大括号括起来,并且显式的将参数名写出来

最后在paintJob里面需要使用参数的时候也不能直接拿来用,需要这样写$$.参数名

这样就成功的将颜色传递给了paintJob函数,实现每一次创建Canvas的时候使用不同的颜色绘制,来看下效果

总结

虽说用ArkTS实现了一个爱心跳动的动效,但是多多少少做的还不太顺手,里面有些细节我琢磨着应该还有更好的办法去处理,或者还得需要配合其他语法点一起才能做出更好的效果,反正再多做几个吧,从里面总结一下经验,争取每一次做的动效都能比前一次有所进步。

相关推荐
疯狂的沙粒2 分钟前
如何在Vue项目中应用TypeScript?应该注意那些点?
前端·vue.js·typescript
小镇程序员17 分钟前
vue2 src_Todolist全局总线事件版本
前端·javascript·vue.js
野槐19 分钟前
前端图像处理(一)
前端
程序猿阿伟27 分钟前
《智能指针频繁创建销毁:程序性能的“隐形杀手”》
java·开发语言·前端
疯狂的沙粒28 分钟前
对 TypeScript 中函数如何更好的理解及使用?与 JavaScript 函数有哪些区别?
前端·javascript·typescript
瑞雨溪37 分钟前
AJAX的基本使用
前端·javascript·ajax
力透键背40 分钟前
display: none和visibility: hidden的区别
开发语言·前端·javascript
程楠楠&M1 小时前
node.js第三方Express 框架
前端·javascript·node.js·express
盛夏绽放1 小时前
Node.js 和 Socket.IO 实现实时通信
前端·后端·websocket·node.js
想自律的露西西★1 小时前
用el-scrollbar实现滚动条,拖动滚动条可以滚动,但是通过鼠标滑轮却无效
前端·javascript·css·vue.js·elementui·前端框架·html5