组件的某些通用属性变化时,可以通过属性动画实现渐变过渡效果,提升用户体验。支持的属性包括width、height、backgroundColor、opacity、scale、rotate、translate等。 本文介绍一下以上几个属性各动画的执行效果,并且实现一个简单的点赞功能,看一下演示效果: 源码:
less
@Entry
@ComponentV2
struct AnimationTest {
@Local stackWigth: number = 0;
@Local stackHeight: number = 0;
@Local x: number = 0 //旋转轴向量x坐标
@Local y: number = 0 //旋转轴向量y坐标
@Local centerX: number = 0 //变换中心点锚点x轴坐标
@Local centerY: number = 0 //变换中心点锚点y轴坐标
@Local angle: number = 0 //旋转角度 //正时相对于旋转轴方向顺时针转动
@Local widthSize: number = 100;
@Local heightSize: number = 50;
@Local bgColor: ResourceColor = Color.Green
@Local opacityChange: number = 1;
@Local scaleOption: ScaleOptions = {
x: 1, //x轴的缩放倍数
y: 1,
z: 1,
centerX: 0, //变换中心点x轴坐标
centerY: 0
}
@Local roateOption: RotateOptions = {
angle: 0
}
@Local translateOption: TranslateOptions = {}
@Local radioBtn1: boolean = false
@Local radioBtn2: boolean = false
@Local radioBtn3: boolean = false
@Local radioBtn4: boolean = false
@Local radioBtn5: boolean = false
@Local radioBtn6: boolean = false
@Local heartOffsetX:number=0
@Local heartOffsetY:number=0
@Local heartAngle:number=0
@Local heartScale:ScaleOptions = {
x: 1.2,
y: 1.2,
}
@Local heartopacity: number = 0
@Local animationStop:boolean = true
build() {
Column({ space: 10 }) {
Stack() {
Button('animation')
.width(this.widthSize)
.height(this.heightSize)
.backgroundColor(this.bgColor)
.opacity(this.opacityChange)//透明度
.scale(this.scaleOption)//设置组件缩放
.rotate(this.roateOption)
.translate(this.translateOption)
}.width('100%')
.height('30%')
.onSizeChange((oldValue: SizeOptions, newValue: SizeOptions) => {
this.stackWigth = newValue.width as number
this.stackHeight = newValue.height as number
})
Row({ space: 5 }) {
Column() {
Text('长宽')
Toggle({ type: ToggleType.Checkbox, isOn: false })
.size({ width: 20, height: 20 })
.onChange((isOn: boolean) => {
this.radioBtn1 = isOn
})
}
Column() {
Text('背景')
Toggle({ type: ToggleType.Checkbox, isOn: false })
.size({ width: 20, height: 20 })
.onChange((isOn: boolean) => {
this.radioBtn2 = isOn
})
}
Column() {
Text('透明度')
Toggle({ type: ToggleType.Checkbox, isOn: false })
.size({ width: 20, height: 20 })
.onChange((isOn: boolean) => {
this.radioBtn3 = isOn
})
}
Column() {
Text('缩放')
Toggle({ type: ToggleType.Checkbox, isOn: false })
.size({ width: 20, height: 20 })
.onChange((isOn: boolean) => {
this.radioBtn4 = isOn
})
}
Column() {
Text('旋转')
Toggle({ type: ToggleType.Checkbox, isOn: false })
.size({ width: 20, height: 20 })
.onChange((isOn: boolean) => {
this.radioBtn5 = isOn
})
}
Column() {
Text('平移')
Toggle({ type: ToggleType.Checkbox, isOn: false })
.size({ width: 20, height: 20 })
.onChange((isOn: boolean) => {
this.radioBtn6 = isOn
})
}
}
Column({ space: 10 }) {
Row({ space: 10 }) {
Text('X:' + this.x)
Slider({
value: this.x,
min: 0,
max: this.stackWigth,
style: SliderStyle.OutSet
})
.onChange((value: number) => {
this.x = value;
})
}
Row({ space: 10 }) {
Text('Y:' + this.y)
Slider({
value: this.y,
min: 0,
max: this.stackHeight,
style: SliderStyle.OutSet
})
.onChange((value: number) => {
this.y = value;
})
}
Row({ space: 10 }) {
Text('centerX:' + this.centerX)
Slider({
value: this.centerX,
min: 0,
max: this.stackWigth,
style: SliderStyle.OutSet
})
.onChange((value: number) => {
this.centerX = value;
})
}
Row({ space: 10 }) {
Text('centerY:' + this.centerY)
Slider({
value: this.centerY,
min: 0,
max: this.stackHeight,
style: SliderStyle.OutSet
})
.onChange((value: number) => {
this.centerY = value;
})
}
Row({ space: 10 }) {
Text('angle:' + this.angle)
Slider({
value: this.angle,
min: -180,
max: 180,
style: SliderStyle.OutSet
})
.onChange((value: number) => {
this.angle = value;
})
}
}.width('80%')
Row() {
Button('执行').onClick(() => {
this.getUIContext().animateTo({
duration: 3000, //动画持续时间,单位为毫秒
curve: Curve.EaseOut, //动画曲线
delay: 100, //动画延迟播放时间,单位为ms(毫秒)
iterations: 1, //动画播放次数
playMode: PlayMode.Normal, //动画播放模式 正向
onFinish: () => { //动画播放完成回调
}
}, () => {
if (this.radioBtn1) {
this.widthSize = 200
this.heightSize = 50
}
if (this.radioBtn2) {
this.bgColor = Color.Red
}
if (this.radioBtn3) {
this.opacityChange = 0.3
}
if (this.radioBtn4) {
this.scaleOption = {
x: 1.5, //x轴的缩放倍数
y: 1.5,
z: 1,
centerX: 0, //变换中心点x轴坐标
centerY: 0
}
}
if (this.radioBtn5) {
this.roateOption = {
x: this.x,
y: this.y,
angle: this.angle,
centerX: this.centerX,
centerY: this.centerY
}
}
if (this.radioBtn6) {
this.translateOption = {
x: 100,
y: 100
}
}
})
})
Button('恢复').onClick(() => {
this.widthSize = 100;
this.heightSize = 50;
this.bgColor = Color.Green
this.opacityChange = 1;
this.scaleOption = {
x: 1, //x轴的缩放倍数
y: 1,
z: 1,
centerX: this.centerX, //变换中心点x轴坐标
centerY: this.centerY
}
this.roateOption = {
angle: 0
}
this.translateOption = {
x: 0,
y: 0
}
})
}
Stack({alignContent:Alignment.Start}) {
Text('点赞动画').fontSize(30)
Image($r('app.media.heart')).width(40).height(40)
.rotate({angle:this.heartAngle})
.position({
x: this.heartOffsetX,
y: this.heartOffsetY
})
.opacity(this.heartopacity)
.scale(this.heartScale)
}.layoutWeight(1).width('100%').backgroundColor(Color.Yellow)
.gesture(
TapGesture({ count: 2 })
.onAction((event: GestureEvent) => {
if (!this.animationStop) return
this.animationStop=false
this.heartOffsetX = event.fingerList[0].localX
this.heartOffsetY = event.fingerList[0].localY
this.heartopacity=1
this.heartAngle=(Math.random()*2-1)*50
setTimeout(()=>{
this.getUIContext().animateTo({
duration: 500, //动画持续时间,单位为毫秒
curve: Curve.EaseOut, //动画曲线
iterations: 1, //动画播放次数
playMode: PlayMode.Normal, //动画播放模式 正向
onFinish: () => { //动画播放完成回调
this.getUIContext().animateTo({
duration: 1000, //动画持续时间,单位为毫秒
curve: Curve.EaseOut, //动画曲线
iterations: 1, //动画播放次数
playMode: PlayMode.Normal, //动画播放模式 正向
onFinish: () => { //动画播放完成回调
this.heartScale = {
x: 1.2,
y: 1.2,
}
this.animationStop = true
}
},()=>{
this.heartScale = {
x: 2,
y: 2,
}
this.heartopacity = 0
})
}
},()=>{
this.heartScale = {
x: 1,
y: 1,
}
})
},100)
})
)
}
}
}