系列文章目录
HarmonyOS Next 系列之省市区弹窗选择器实现(一)
HarmonyOS Next 系列之验证码输入组件实现(二)
HarmonyOS Next 系列之底部标签栏TabBar实现(三)
HarmonyOS Next 系列之HTTP请求封装和Token持久化存储(四)
HarmonyOS Next 系列之从手机选择图片或拍照上传功能实现(五)
HarmonyOS Next 系列之可移动悬浮按钮实现(六)
HarmonyOS Next 系列之沉浸式状态实现的多种方式(七)
HarmonyOS Next系列之Echarts图表组件(折线图、柱状图、饼图等)实现(八)
HarmonyOS Next系列之地图组件(Map Kit)使用(九)
HarmonyOS Next系列之半圆环进度条实现(十)
HarmonyOS Next 系列之列表下拉刷新和触底加载更多数据实现(十一)
HarmonyOS Next系列之实现一个左右露出中间大两边小带缩放动画的轮播图(十二)
HarmonyOS Next系列之水波纹动画特效实现(十三)
前言
HarmonyOS Next(基于API12)实现水波纹动画特效。
一、实现原理
画3个等比例放大的圆形,通过显示动画animateTo动态改变圆形放大系数和透明度
二、显式动画 (animateTo)使用回顾
animateTo显式动画接口来指定由于闭包代码导致的状态变化插入过渡动效。同属性动画,布局类改变宽高的动画,内容都是直接到终点状态
入参
animateTo(value: AnimateParam, event: () => void): void
说明:
value 设置动画参数例如动画时长、动画速度、动画延迟等。
event:回调函数,指定组件最终状态,动画将从初始态到最终态自动插入过度动画
AnimateParam常用属性:
名称 | 类型 | 说明 |
---|---|---|
duration | number | 动画持续时长,单位ms |
curve | Curve Curve9+ string | 动画曲线默认值Curve.EaseInOut |
delay | number | 动画延迟执行时间单位ms |
iterations | number | 动画播放次数,默认播放一次,设置为-1时表示无限次播放。设置为0时表示无动画效果 |
playMode | PlayMode | 动画播放模式,默认播放完成后重头开始播放 |
显示动画需要有个触发点去调用animateTo(),绑定在哪个组件上就需要在当前组件的事件下调用animateTo()动画才能生效。
常见使用场景放置点击事件,不符合我们当前要实现的。实现水波纹动画需要组件渲染完自动触发动画,所以我们可以考虑放在组件的onAppear事件上,onAppear为组件挂载显示后触发此回调。
更多显式动画 (animateTo)使用请看官方文档
三、代码实现
示例一:
图标水波纹动画特效:
@Entry
@Component
struct Demo {
@State scaleList: number[] = [] //缩放比例数据
@State opacityList: number[] = [] //透明度数据
private cloneScaleList: number[] = [] //备份初始缩放比例数据
private cloneOpacityList: number[] = [] //备份初始透明度数据
private scaleRatio:number=0.7 //缩放增大比例
aboutToAppear(): void {
//初始化缩放比例和透明度,新建数组保存3个圆形对应数据
//缩放比例:[1,1.7,2.4] 透明度:[0.3,0.2,0.1]
this.scaleList = new Array(3).fill('').map((item: string, index: number) => 1 + index * this.scaleRatio)
this.opacityList = new Array(3).fill('').map((item: string, index: number) => (3 - index)/10 )
this.cloneScaleList = this.scaleList.slice()
this.cloneOpacityList = this.opacityList.slice()
}
build() {
Column({ space: 50 }) {
Stack() {
ForEach(this.scaleList, (item: number, index: number) => {
Column() {
}
.width(50)
.height(50)
.borderRadius(25)
.backgroundColor('#1463F4')
.opacity(this.opacityList[index])
.scale({ x: this.scaleList[index], y: this.scaleList[index] })
.onAppear(() => {
animateTo({ duration: 1200, iterations: -1 }, () => {
//每个圆缩放系数+0.7
this.scaleList[index] = this.cloneScaleList[index] + this.scaleRatio
//每个圆透明度-0.1
this.opacityList[index] = this.cloneOpacityList[index] - 0.1
})
})
}, (item: number, index: number) => index.toString())
Image($r('app.media.app_icon')).width(50).borderRadius(25)
}
}.height('100%').width('100%').justifyContent(FlexAlign.Center).alignItems(HorizontalAlign.Center)
}
}
运行效果:
说明:初始化新建了3个圆形,通过变量scaleList保存了3个圆初始缩放比例为 [1,1.7,2.4],通过变量opacityList保存了初始透明度为[0.3,0.2,0.1],在每个圆的渲染完成回调函数onAppear中调用显示动画把每个圆增大0.7倍,变成[1.7,2.4,3.1],同时透明度减0.1,变成[0.2,0.1,0],动画属性设置iterations: -1循环播放,就形成了水波纹动画效果。
示例二:
按钮水波纹特效:
@Entry
@Component
struct Demo {
@State scaleList: number[] = [] //缩放比例数据
@State opacityList: number[] = [] //透明度数据
private cloneScaleList: number[] = [] //备份初始缩放比例数据
private cloneOpacityList: number[] = [] //备份初始透明度数据
private scaleRatio: number = 0.3 //缩放增大比例
aboutToAppear(): void {
//初始化缩放比例和透明度
this.scaleList = new Array(2).fill('').map((item: string, index: number) => 1 + index * this.scaleRatio)
this.opacityList = new Array(2).fill('').map((item: string, index: number) => 0.3-index*0.15)
this.cloneScaleList = this.scaleList.slice()
this.cloneOpacityList = this.opacityList.slice()
}
build() {
Column({ space: 50 }) {
Stack() {
ForEach(this.scaleList, (item: number, index: number) => {
Column() {
}
.width(120)
.height(50)
.borderRadius(25)
.backgroundColor('#007DFE')
.opacity(this.opacityList[index])
.scale({ x: this.scaleList[index], y: this.scaleList[index] })
.onAppear(() => {
animateTo({ duration: 1000, iterations: -1 }, () => {
this.scaleList[index] = this.cloneScaleList[index] + this.scaleRatio
this.opacityList[index] = this.cloneOpacityList[index] - 0.15
})
})
}, (item: number, index: number) => index.toString())
Button('提交', { type: ButtonType.Capsule }).width(120).height(50).borderRadius(25)
}
}.height('100%').width('100%').justifyContent(FlexAlign.Center).alignItems(HorizontalAlign.Center)
}
}
运行效果: