一、定义
当组件的通用属性发生改变时而产生的属性渐变效果
说明:
当组件的通用属性发生改变时,组件状态由初始状态逐渐变为结束状态的过程中,会创建多个连续的中间状态,逐帧播放后,就会形成动画
二、创建
给组件(如lmage、Button、 Column等)添加animation属性,并设置属性动画的参数
参数:
- duration:动画时长,单位为毫秒,默认时长为1000毫秒
- tempo:动画的播放速度,值越大动画播放越快,值越小播放越慢,为0时无动画效果,默认值:1
- curve:动画变化曲线,默认曲线为线性,默认值是:Curve.Linear
名称 | 描述 |
---|---|
Linear | 表示动画从头到尾的速度都是相同的。 |
Ease | 表示动画以低速开始,然后加快,在结束前变慢,CubicBezier(0.25, 0.1, 0.25, 1.0)。 |
EaseIn | 表示动画以低速开始,CubicBezier(0.42, 0.0, 1.0, 1.0)。 |
EaseOut | 表示动画以低速结束,CubicBezier(0.0, 0.0, 0.58, 1.0)。 |
EaseInOut | 表示动画以低速开始和结束,CubicBezier(0.42, 0.0, 0.58, 1.0)。 |
FastOutSlowIn | 标准曲线,cubic-bezier(0.4, 0.0, 0.2, 1.0)。 |
LinearOutSlowIn | 减速曲线,cubic-bezier(0.0, 0.0, 0.2, 1.0)。 |
FastOutLinearIn | 加速曲线,cubic-bezier(0.4, 0.0, 1.0, 1.0)。 |
ExtremeDeceleration | 急缓曲线,cubic-bezier(0.0, 0.0, 0.0, 1.0)。 |
Sharp | 锐利曲线,cubic-bezier(0.33, 0.0, 0.67, 1.0)。 |
Rhythm | 节奏曲线,cubic-bezier(0.7, 0.0, 0.2, 1.0)。 |
Smooth | 平滑曲线,cubic-bezier(0.4, 0.0, 0.4, 1.0)。 |
Friction | 阻尼曲线,CubicBezier(0.2, 0.0, 0.2, 1.0)。 |
- delay:延时播放时间,单位为毫秒,默认值:0,不延时播放
- iterations:播放次数,默认值:1,设置为-1时表示无限次播放
- playMode:设置动画播放模式,默认:播放完成后重头开始播放
名称 | 描述 |
---|---|
Normal | 动画按正常播放 |
Reverse | 动画反向播放 |
Alternate | 动画在奇数次(1、3、5...)正向播放,在偶数次(2、4、6...)反向播放 |
AlternateReverse | 动画在奇数次(1、3、5...)反向播放,在偶数次(2、4、6...)正向播放 |
- onFinish:动画播放结束时回调
三、使用:
Image($r('app.media._icon'))
.animation({
duration: 1000,
tempo: 1.0,
delay: 0,
curve: Curve.Linear,
playMode: PlayMode.Normal,
iterations: 1
})
发现动画并未执行,原因可能如下:
- 产生属性动画的属性需要在animation之前声明
- 产生属性动画的属性变化时需触发UI状态更新
- 产生属性动画的属性本身需满足一定的要求,并非任何属性都可以产生属性动画。目前支持的属性包括width、height、position、opacity、backgroundColor、scale、rotate、translate等
三、案例
旋转动画 rotate
@Entry
@Component
struct AnimPage {
@State rotateAngle: number = 0
build() {
Row() {
Column() {
Button("开启旋转动画", { type: ButtonType.Capsule, stateEffect: true })
.onClick(() => {
this.rotateAngle = 360
})
Row({ space: 20 }) {
//沿着X轴旋转
Image($r('app.media.app_icon'))
.width(80)
.height(80)
.rotate({ x: 1, y: 0, z: 0, angle: this.rotateAngle })
.animation({
duration: 2000,
tempo: 1.0,
delay: 0,
curve: Curve.Linear,
playMode: PlayMode.Normal,
iterations: -1
})
//沿着Y轴旋转
Image($r('app.media.app_icon'))
.width(80)
.height(80)
.rotate({ x: 0, y: 1, z: 0, angle: this.rotateAngle })
.animation({
duration: 2000,
tempo: 1.0,
delay: 0,
curve: Curve.Linear,
playMode: PlayMode.Normal,
iterations: -1
})
//沿着Z轴旋转
Image($r('app.media.app_icon'))
.width(80)
.height(80)
.rotate({ x: 0, y: 0, z: 1, angle: this.rotateAngle })
.animation({
duration: 2000,
tempo: 1.0,
delay: 0,
curve: Curve.Linear,
playMode: PlayMode.Normal,
iterations: -1
})
Image($r('app.media.app_icon'))
.width(80)
.height(80)
.rotate({ x: 0, y: 0, z: 1, angle: this.rotateAngle })
.animation({
duration: 2000,
tempo: 1.0,
delay: 0,
//低速开始,然后加快,在结束前变慢
curve: Curve.Ease,
//
playMode: PlayMode.Reverse,
iterations: -1
})
}
.margin({ top: 20 })
.padding({ left: 10 })
.height("30%")
.width("100%")
.backgroundColor(Color.Red)
}
.width('100%')
}
.height('100%')
}
}
位移动画 position
@Entry
@Component
struct AnimPage {
@State xState: number = 0
@State yState: number = 0
build() {
Row() {
Column() {
Row() {
Text('位移动画')
.width(200)
.height(100)
.fontColor(Color.Blue)
.fontSize(30)
.margin(100)
.position({ x: this.xState, y: 0 })
.animation({
duration: 1000,
tempo: 1.0,
delay: 0,
curve: Curve.Linear,
playMode: PlayMode.Normal,
iterations: 1,
onFinish: () => {
this.xState = 200
}
})
Image($r('app.media.app_icon'))
.width(80)
.height(80)
.position({ x: 0, y: this.yState })
.animation({
duration: 1000,
tempo: 1.0,
delay: 0,
curve: Curve.Linear,
playMode: PlayMode.Normal,
iterations: 1,
onFinish: () => {
//在onFinish回调中重新设置了xState和yState,也可以实现永久播放的效果
if (this.yState == 0) {
this.yState = 200
} else {
this.yState = 0
}
}
})
}
.height("30%")
.width("100%")
.backgroundColor(Color.Red)
}
.width('100%')
}
.height('100%')
}
}
缩放动画 width、height
@Entry
@Component
struct AnimPage {
@State widthSize: number = 250
@State heightSize: number = 100
@State flag: boolean = true
build() {
Row() {
Column() {
Button('缩放')
.onClick(() => {
if (this.flag) {
this.widthSize = 150
this.heightSize = 60
} else {
this.widthSize = 250
this.heightSize = 100
}
this.flag = !this.flag
})
.margin(30)
.width(this.widthSize)
.height(this.heightSize)
.animation({
duration: 2000,
curve: Curve.EaseOut,
iterations: 3,
playMode: PlayMode.Normal
})
}.width('100%')
.height('30%')
.backgroundColor(Color.Red)
}
.width('100%')
.height('100%')
}
}
透明度动画 opacity
@Entry
@Component
struct AnimPage {
@State opacityAngle: number = 1
build() {
Row() {
Column() {
Button('透明度')
.onClick(() => {
this.opacityAngle = 0
})
.margin(50)
.opacity(this.opacityAngle)
.animation({
duration: 2000,
curve: Curve.Friction,
delay: 500,
iterations: -1, // 设置-1表示动画无限循环
playMode: PlayMode.Alternate
})
}.width('100%')
.height('30%')
.backgroundColor(Color.Red)
}
.width('100%')
.height('100%')
}
}