• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# 定义可动画属性 (@AnimatableExtend)
2<!--Kit: ArkUI-->
3<!--Subsystem: ArkUI-->
4<!--Owner: @hehongyang3-->
5<!--Designer: @yangfan229-->
6<!--Tester: @lxl007-->
7<!--Adviser: @HelloCrease-->
8
9@AnimatableExtend装饰器用于自定义可动画的属性方法,该装饰器内定义的函数在动画过程中会被逐帧调用,直到动画结束。该装饰器的常见用途有:
10
111. 使不可动画属性变为可动画属性,自定义数据运算规则使得属性能进行插值运算得到中间结果,再由动画驱动属性从起点值逐渐过渡到终点值。
12
132. 使属性逐帧变化,实现逐帧布局的效果。
14
15- 可动画属性:如果一个属性方法在animation属性前调用,改变这个属性的值可以使animation属性的动画效果生效,属性有动画过渡效果,这个属性称为可动画属性。比如height、width、backgroundColor、translate属性,和Text组件的fontSize属性等。
16
17- 不可动画属性:如果一个属性方法在animation属性前调用,改变这个属性的值不能使animation属性的动画效果生效,属性突变无动画效果,这个属性称为不可动画属性。比如Polyline组件的points属性等。
18
19>  **说明:**
20>
21>  该装饰器从API version 10开始支持。后续版本如有新增内容,则采用上角标单独标记该内容的起始版本。
22
23## 语法
24
25```ts
26@AnimatableExtend(UIComponentName) function functionName(value: typeName) {
27  .propertyName(value)
28}
29```
30
31- \@AnimatableExtend仅支持定义在全局,不支持在组件内部定义。
32- \@AnimatableExtend定义的函数参数类型必须为number类型或者实现 AnimatableArithmetic\<T\>接口的自定义类型。
33- \@AnimatableExtend定义的函数体内只能调用\@AnimatableExtend括号内组件的属性方法。
34
35## AnimatableArithmetic\<T\>
36
37该接口定义非number数据类型的动画运算规则。对非number类型的数据(如数组、结构体、颜色等)做动画,需要实现AnimatableArithmetic\<T\>接口中加法、减法、乘法和判断相等函数,
38使得该数据能参与动画的插值运算和识别该数据是否发生改变。即定义它们为实现了AnimatableArithmetic\<T\>接口的类型。
39
40**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
41
42**系统能力:** SystemCapability.ArkUI.ArkUI.Full
43
44### plus
45
46plus(rhs: AnimatableArithmetic\<T\>): AnimatableArithmetic\<T\>
47
48定义数据类型的加法运算规则。
49
50**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
51
52**系统能力:** SystemCapability.ArkUI.ArkUI.Full
53
54**参数:**
55
56| 参数名   | 类型                                | 必填 | 说明                                    |
57| ----- | --------------------------------- | ---- | ------------------------------------- |
58| rhs | [AnimatableArithmetic\<T\>](#animatablearithmetict) | 是    | 加法运算的对象。                           |
59
60**返回值:**
61
62| 类型                                       | 说明      |
63| ---------------------------------------- | ------- |
64| [AnimatableArithmetic\<T\>](#animatablearithmetict) | 加法运算的结果。  |
65
66### subtract
67
68subtract(rhs: AnimatableArithmetic\<T\>): AnimatableArithmetic\<T\>
69
70定义该数据类型的减法运算规则。
71
72**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
73
74**系统能力:** SystemCapability.ArkUI.ArkUI.Full
75
76**参数:**
77
78| 参数名   | 类型                                | 必填 | 说明                                    |
79| ----- | --------------------------------- | ---- | ------------------------------------- |
80| rhs | [AnimatableArithmetic\<T\>](#animatablearithmetict) | 是    | 减法运算的对象。                           |
81
82**返回值:**
83
84| 类型                                       | 说明      |
85| ---------------------------------------- | ------- |
86| [AnimatableArithmetic\<T\>](#animatablearithmetict) | 减法运算的结果。  |
87
88### multiply
89
90multiply(scale: number): AnimatableArithmetic\<T\>
91
92定义该数据类型的乘法运算规则。
93
94**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
95
96**系统能力:** SystemCapability.ArkUI.ArkUI.Full
97
98**参数:**
99
100| 参数名   | 类型                                | 必填 | 说明                                    |
101| ----- | --------------------------------- | ---- | ------------------------------------- |
102| scale | number | 是    | 乘法运算的系数。                           |
103
104**返回值:**
105
106| 类型                                       | 说明      |
107| ---------------------------------------- | ------- |
108| [AnimatableArithmetic\<T\>](#animatablearithmetict) | 乘法运算的结果。  |
109
110### equals
111
112equals(rhs: AnimatableArithmetic\<T\>): boolean
113
114定义该数据类型的相等判断规则。
115
116**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
117
118**系统能力:** SystemCapability.ArkUI.ArkUI.Full
119
120**参数:**
121
122| 参数名   | 类型                                | 必填 | 说明                                    |
123| ----- | --------------------------------- | ---- | ------------------------------------- |
124| rhs | [AnimatableArithmetic\<T\>](#animatablearithmetict) | 是    |  和自身比较相等的另一个数据对象。                          |
125
126**返回值:**
127
128| 类型                                       | 说明      |
129| ---------------------------------------- | ------- |
130| boolean | 是否相等。返回true表示相等,返回false表示不相等。  |
131
132## 示例
133
134### 示例1(逐帧布局的效果)
135
136以下示例通过改变Text组件宽度实现逐帧布局的效果。
137
138```ts
139@AnimatableExtend(Text)
140function animatableWidth(width: number) {
141  .width(width)
142}
143
144@Entry
145@Component
146struct AnimatablePropertyExample {
147  @State textWidth: number = 80;
148
149  build() {
150    Column() {
151      Text("AnimatableProperty")
152        .animatableWidth(this.textWidth)
153        .animation({ duration: 2000, curve: Curve.Ease })
154      Button("Play")
155        .onClick(() => {
156          this.textWidth = this.textWidth == 80 ? 160 : 80;
157        })
158    }.width("100%")
159    .padding(10)
160  }
161}
162```
163
164![animatableExtend](figures/AnimatableProperty.gif)
165
166### 示例2(折线的动画效果)
167
168以下示例实现折线的动画效果。
169
170```ts
171class Point {
172  x: number
173  y: number
174
175  constructor(x: number, y: number) {
176    this.x = x
177    this.y = y
178  }
179
180  plus(rhs: Point): Point {
181    return new Point(this.x + rhs.x, this.y + rhs.y);
182  }
183
184  subtract(rhs: Point): Point {
185    return new Point(this.x - rhs.x, this.y - rhs.y);
186  }
187
188  multiply(scale: number): Point {
189    return new Point(this.x * scale, this.y * scale);
190  }
191
192  equals(rhs: Point): boolean {
193    return this.x === rhs.x && this.y === rhs.y;
194  }
195}
196
197// PointVector实现了AnimatableArithmetic<T>接口
198class PointVector extends Array<Point> implements AnimatableArithmetic<PointVector> {
199  constructor(value: Array<Point>) {
200    super();
201    value.forEach(p => this.push(p));
202  }
203
204  plus(rhs: PointVector): PointVector {
205    let result = new PointVector([]);
206    const len = Math.min(this.length, rhs.length);
207    for (let i = 0; i < len; i++) {
208      result.push((this as Array<Point>)[i].plus((rhs as Array<Point>)[i]));
209    }
210    return result;
211  }
212
213  subtract(rhs: PointVector): PointVector {
214    let result = new PointVector([]);
215    const len = Math.min(this.length, rhs.length);
216    for (let i = 0; i < len; i++) {
217      result.push((this as Array<Point>)[i].subtract((rhs as Array<Point>)[i]));
218    }
219    return result;
220  }
221
222  multiply(scale: number): PointVector {
223    let result = new PointVector([]);
224    for (let i = 0; i < this.length; i++) {
225      result.push((this as Array<Point>)[i].multiply(scale));
226    }
227    return result;
228  }
229
230  equals(rhs: PointVector): boolean {
231    if (this.length != rhs.length) {
232      return false;
233    }
234    for (let i = 0; i < this.length; i++) {
235      if (!(this as Array<Point>)[i].equals((rhs as Array<Point>)[i])) {
236        return false;
237      }
238    }
239    return true;
240  }
241
242  get(): Array<Object[]> {
243    let result: Array<Object[]> = [];
244    this.forEach(p => result.push([p.x, p.y]));
245    return result;
246  }
247}
248
249@AnimatableExtend(Polyline)
250function animatablePoints(points: PointVector) {
251  .points(points.get())
252}
253
254@Entry
255@Component
256struct AnimatablePropertyExample {
257  @State points: PointVector = new PointVector([
258    new Point(50, Math.random() * 200),
259    new Point(100, Math.random() * 200),
260    new Point(150, Math.random() * 200),
261    new Point(200, Math.random() * 200),
262    new Point(250, Math.random() * 200),
263  ])
264
265  build() {
266    Column() {
267      Polyline()
268        .animatablePoints(this.points)
269        .animation({ duration: 1000, curve: Curve.Ease })// 设置动画参数
270        .size({ height: 220, width: 300 })
271        .fill(Color.Green)
272        .stroke(Color.Red)
273        .backgroundColor('#eeaacc')
274      Button("Play")
275        .onClick(() => {
276          // points是实现了可动画协议的数据类型,points在动画过程中可按照定义的运算规则、动画参数从之前的PointVector变为新的PointVector数据,产生每一帧的PointVector数据,进而产生动画
277          this.points = new PointVector([
278            new Point(50, Math.random() * 200),
279            new Point(100, Math.random() * 200),
280            new Point(150, Math.random() * 200),
281            new Point(200, Math.random() * 200),
282            new Point(250, Math.random() * 200),
283          ]);
284        })
285    }.width("100%")
286    .padding(10)
287  }
288}
289```
290![image](figures/animatable-points.gif)