ArkUI 开发实例:快五一了,做一个回家的订票动画界面(下

背景

承接上篇和中篇,我们已经实现了整个页面的布局和功能逻辑,那么本章我们开始实现最后的动画效果吧。

订票动画.gif

继续实例

属性动画 (animation)

image.png

分析动效,当我们点击切换出发地和目的地按钮时,火车后面的刷新图标会进行旋转,这种组件的旋转通用属性变化时实现的动画效果,就是属性动画。

支持的属性包括widthheightbackgroundColoropacityscalerotatetranslate等。

我们本次需要修改旋转参数,先在build()前增加一个带状态的变量

1
less复制代码@State rotateValue: number = 0; // 火车图标旋转角度

然后为当前图标增加旋转角度的属性

1
2
3
scss复制代码Image("/pages/ComponentClassification/ExampleComponents/OneReserve/reverse.png")
.width(40)
.rotate({ angle: this.rotateValue })

最后增加动画,动画支持以下的参数对象:

名称 类型 是否必填 描述
duration number 动画持续时间,单位为毫秒。 默认值:1000
tempo number 动画播放速度,值越大动画播放越快,值越小播放越慢,为0时无动画效果。 默认值:1.0
curve Curve或ICurve或string 动画曲线。 默认值:Curve.EaseInOut
delay number 动画延迟播放时间,单位为ms(毫秒),默认不延时播放。
iterations number 动画播放次数。默认播放一次,设置为-1时表示无限次播放。设置为0时表示无动画效果。
playMode PlayMode 动画播放模式,默认播放完成后重头开始播放。 默认值:PlayMode.Normal
onFinish () => void 动画播放完成回调。 从API version 9开始,该接口支持在ArkTS卡片中使用。
finishCallbackType FinishCallbackType 在动画中定义onFinish回调的类型。 默认值:FinishCallbackType.REMOVED
expectedFrameRateRange ExpectedFrameRateRange 设置动画的期望帧率。

根据上上述表格,动画效果默认是1000ms,默认执行一次,默认无延迟,那么我们只需要将曲线修改成EaseOut即可,此时图片代码如下:

1
2
3
4
5
6
scss复制代码Image("/pages/ComponentClassification/ExampleComponents/OneReserve/reverse.png")
.width(40)
.rotate({ angle: this.rotateValue })
.animation({
curve: Curve.EaseOut,
})

最后,回到当前按钮,设置当按钮点击后,旋转角度360度即可,按钮事件修改如下:

1
2
3
4
5
kotlin复制代码.onClick(() => {
this.ifSwitch = !this.ifSwitch;
this.ifStartSearch = false
this.rotateValue = this.rotateValue + 360;
})

按钮动画.gif

如上图所示,当前切换动画旋转效果已经实现,但是其他地方还是很生硬的,那么我们继续后续效果,接下来我们不再采用属性动画效果,而是通过转场方式实现。

组件内转场 (transition)

当用户组件出现和删除时,可以通过transition属性配置过度的动画效果,即为组件内转场动画。

其包含的参数对象如下:

接口名称 参数类型 是否静态函数 参数描述
opacity number 设置组件转场时的透明度效果,为插入时起点和删除时终点的值。 取值范围: [0, 1]
translate TranslateOptions 设置组件转场时的平移效果,为插入时起点和删除时终点的值。 -x:横向的平移距离。 -y:纵向的平移距离。 -z:竖向的平移距离。
scale ScaleOptions 设置组件转场时的缩放效果,为插入时起点和删除时终点的值。 -x:横向放大倍数(或缩小比例)。 -y:纵向放大倍数(或缩小比例)。 -z:当前为二维显示,该参数无效 。 - centerX、centerY指缩放中心点,centerX和centerY默认值是”50%”,即默认以组件的中心点为缩放中心点。 - 中心点为(0, 0)代表组件的左上角。
rotate RotateOptions 设置组件转场时的旋转效果,为插入时起点和删除时终点的值。 -x:横向的旋转向量分量。 -y:纵向的旋转向量分量。 -z:竖向的旋转向量分量。 - centerX、centerY指旋转中心点,centerX和centerY默认值是”50%”,即默认以组件的中心点为旋转中心点。 - 中心点为(0, 0)代表组件的左上角。 -centerZ指z轴锚点,即3D旋转中心点的z轴分量,centerZ默认值是0。 -perspective指视距,即视点到z=0平面的距离,perspective默认值是0。
move TransitionEdge 指定组件转场时从屏幕边缘滑入和滑出的效果,本质为平移效果,为插入时起点和删除时终点的值。
asymmetric appear: TransitionEffect, disappear: TransitionEffect 指定非对称的转场效果。 第一个参数指定出现的转场效果,第二个参数指定消失的转场效果。 如不通过asymmetric函数构造TransitionEffect,则表明该效果在组件出现和消失时均生效。
combine TransitionEffect 对TransitionEffect进行链式组合,以形成包含多种转场效果的TransitionEffect。
animation AnimateParam 指定该TransitionEffect的动画参数。 该参数只用来指定动画参数,其入参AnimateParam的onFinish回调不生效。 如果通过combine进行TransitionEffect的组合,前一TransitionEffect的动画参数也可用于后一TransitionEffect。

表格内容看似很复杂,特别是最好还有一些组合效果,但是我们先实战下简单的转场效果,实现出发地和目的地的对调,很明显这时候我们需要用到平移转场。

我们在出发地容器最后面增加转场效果,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
scss复制代码Column({ space: 5 }) {
Text("信阳")
.fontSize(20)
.fontWeight(FontWeight.Medium)
.fontColor("#132968")
Text("XinYang")
.fontSize(13)
.fontColor("#132968")
}
.width(70)
.transition(
TransitionEffect.translate({
x: 200,
y: 0,
z: 0
}).animation({ duration: 1000 })
)

代表出场和入场时从x方向200的位置偏移1000ms过来。

位移出场动画.gif

很明显效果还是很生硬,我们需要加入透明度效果,实现柔和的过渡,此时需要将透明度与位移动画进行融合。

增加透明度动画后代码如下:

1
2
3
4
5
6
7
8
9
10
less复制代码.transition(
TransitionEffect.OPACITY.animation({ duration: 500, curve: Curve.LinearOutSlowIn })
.combine(
TransitionEffect.translate({
x: 200,
y: 0,
z: 0
}).animation({ duration: 1000 })
)
)

位移出场动画2.gif

很好此时动画效果很完美,那么我们在目的地也加上相应的代码即可。

目前按钮箭头还是很生硬,按钮之前我们专门切了两张图,这是因为我们需要实现垂直轴旋转的动画效果,所以我们在两张箭头图上增加沿着y轴旋转的转场180度的动画效果,当然也要加入透明度转场,此时代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
less复制代码Button() {
if (!this.ifSwitch) {
Image("/pages/ComponentClassification/ExampleComponents/OneReserve/buttonArrow.png")
.width(40)
.transition(
TransitionEffect.OPACITY.animation({ duration: 1000, curve: Curves.springCurve(10, 1, 268, 23) })
.combine(
TransitionEffect.rotate({ y: 1, angle: 180 }).animation({ duration: 1000 }))
)
}
else {
Image("/pages/ComponentClassification/ExampleComponents/OneReserve/buttonArrowReverse.png")
.width(40)
.transition(
TransitionEffect.OPACITY.animation({ duration: 1000, curve: Curves.springCurve(10, 1, 268, 23) })
.combine(
TransitionEffect.rotate({ y: 1, angle: 180 }).animation({ duration: 1000 }))
)
}
}
.backgroundColor("#DEEBF9")
.width(40)
.onClick(() => {
this.ifSwitch = !this.ifSwitch;
this.ifStartSearch = false
this.rotateValue = this.rotateValue + 360;
})

注:此时我们用了自定义曲线,需要引入曲线模板,在当前ets顶部增加如下代码即可:

1
javascript复制代码import Curves from '@ohos.curves'

位移出场动画3.gif

最后,加下日期选择器切换到订票信息的动画效果了,

日期选择器有一个缩放的转场效果,我们在日期选择器下增加下面代码:

1
2
3
4
5
6
7
8
less复制代码.transition(
TransitionEffect.OPACITY.animation({ duration: 1000, curve: Curves.springCurve(10, 1, 268, 23) }).combine(
TransitionEffect.scale({
x: 0,
y: 0,
}).animation({ duration: 700, curve: Curves.springCurve(10, 1, 268, 23), })
)
)

此时日期选择器出现和消失时候就有缩放的动画了。

最后一步,为订票信息增加动画就好了,不过里面的信息有明显顺序,此时我们需要用到delay参数即可,为组件增加递增的delay效果。代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
less复制代码Column() {
Row({ space: 15 }) {
Column({ space: 10 }) {
Text("日期")
.fontSize(15)
.fontWeight(FontWeight.Normal)
.fontColor("#A1A9C3")
Text((this.selectedDate.getMonth() + 1).toString() + "月" + (this.selectedDate.getDate()).toString() + "日")
.fontSize(17)
.fontColor("#132968")
}
.width(80)
.transition(
TransitionEffect.OPACITY.animation({ duration: 1000, curve: Curves.springCurve(10, 1, 268, 23) })
.combine(
TransitionEffect.scale({
x: 0,
y: 0,
}).animation({ duration: 700, curve: Curves.springCurve(10, 1, 268, 23), })
)
)

Column({ space: 10 }) {
Text("时间")
.fontSize(15)
.fontWeight(FontWeight.Normal)
.fontColor("#A1A9C3")
Text("10:08")
.fontSize(17)
.fontColor("#132968")
}
.width(80)
.transition(
TransitionEffect.OPACITY.animation({
delay: 200,
duration: 1000,
curve: Curves.springCurve(10, 1, 268, 23)
}).combine(
TransitionEffect.scale({
x: 0,
y: 0,
}).animation({ delay: 200, duration: 700, curve: Curves.springCurve(10, 1, 268, 23), })
)
)

Column({ space: 10 }) {
Text("车次")
.fontSize(15)
.fontWeight(FontWeight.Normal)
.fontColor("#A1A9C3")
Text("Z225")
.fontSize(17)
.fontColor("#132968")
}
.width(80)
.transition(
TransitionEffect.OPACITY.animation({
delay: 400,
duration: 1000,
curve: Curves.springCurve(10, 1, 268, 23)
}).combine(
TransitionEffect.scale({
x: 0,
y: 0,
}).animation({ delay: 400, duration: 700, curve: Curves.springCurve(10, 1, 268, 23), })
)
)
}

Row({ space: 15 }) {
Column({ space: 10 }) {
Text("车厢")
.fontSize(15)
.fontWeight(FontWeight.Normal)
.fontColor("#A1A9C3")
Text("07车")
.fontSize(17)
.fontColor("#132968")
}
.width(80)
.transition(
TransitionEffect.OPACITY.animation({
delay: 600,
duration: 1000,
curve: Curves.springCurve(10, 1, 268, 23)
}).combine(
TransitionEffect.scale({
x: 0,
y: 0,
}).animation({ delay: 600, duration: 700, curve: Curves.springCurve(10, 1, 268, 23), })
)
)

Column({ space: 10 }) {
Text("座位号")
.fontSize(15)
.fontWeight(FontWeight.Normal)
.fontColor("#A1A9C3")
Text("061号")
.fontSize(17)
.fontColor("#132968")
}
.width(80)
.transition(
TransitionEffect.OPACITY.animation({
delay: 800,
duration: 1000,
curve: Curves.springCurve(10, 1, 268, 23)
}).combine(
TransitionEffect.scale({
x: 0,
y: 0,
}).animation({ delay: 800, duration: 700, curve: Curves.springCurve(10, 1, 268, 23), })
)
)

Column({ space: 10 }) {
Text("票价")
.fontSize(15)
.fontWeight(FontWeight.Normal)
.fontColor("#A1A9C3")
Text("210.0元")
.fontSize(17)
.fontColor("#132968")
}
.width(80)
.transition(
TransitionEffect.OPACITY.animation({
delay: 1000,
duration: 1000,
curve: Curves.springCurve(10, 1, 268, 23)
}).combine(
TransitionEffect.scale({
x: 0,
y: 0,
}).animation({ delay: 1000, duration: 700, curve: Curves.springCurve(10, 1, 268, 23), })
)
)
}
}
.justifyContent(FlexAlign.SpaceAround)
.height(165)

搞定,当前实例完成,看下最终效果吧。

订票动画.gif

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%