• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# \@AnimatableExtend Decorator: Definition of Animatable Attributes
2
3The @AnimatableExtend decorator is used to define an attribute method for the non-animatable attribute of a component. During animation execution, a frame-by-frame callback is used to change the value of the non-animatable attribute so that an animation effect can be applied to the attribute.
4
5- Animatable attribute: If an attribute method is called before the **animation** attribute, and changing the value of this attribute can make the animation effect specified by the **animation** attribute take effect, then this attribute is called animatable attribute. For example, **height**, **width**, **backgroundColor**, **translate**, and **fontSize** (of the **\<Text>** component) are all animatable attributes.
6
7- Non-animatable attribute: If an attribute method is called before the **animation** attribute, and changing the value of this attribute cannot make the animation effect specified by the **animation** attribute take effect, then this attribute is called non-animatable attribute. For example, the **points** attribute of the **\<Ployline>** component is a non-animatable attribute.
8
9>  **NOTE**
10>
11>  This decorator is supported since API version 10. Updates will be marked with a superscript to indicate their earliest API version.
12
13## Rules of Use
14
15
16### Syntax
17
18
19```ts
20@AnimatableExtend(UIComponentName) function functionName(value: typeName) {
21  .propertyName(value)
22}
23```
24
25- \@AnimatableExtend can be defined only globally.
26- The parameter of the \@AnimatableExtend decorated function must be of the number type or a custom type that implements the **AnimtableArithmetic\<T\>** API.
27- In the \@AnimatableExtend decorated function body, only the attribute methods of the component specified in brackets immediately following \@AnimatableExtend can be called.
28
29### AnimtableArithmetic\<T\> Description
30To perform animation when complex data types are involved, you must implement the addition, subtraction, multiplication, and equivalence judgment functions in the **AnimtableArithmetic\<T\>** API.
31| Name| Input Parameter Type| Return Value Type| Description
32| -------- | -------- |-------- |-------- |
33| plus | AnimtableArithmetic\<T\> | AnimtableArithmetic\<T\> | Addition function.|
34| subtract | AnimtableArithmetic\<T\> | AnimtableArithmetic\<T\> | Subtraction function.|
35| multiply | number | AnimtableArithmetic\<T\> | Multiplication function.|
36| equals | AnimtableArithmetic\<T\> | boolean | Equivalence judgment function.|
37
38## Example
39
40The following example applies an animation to the font size attribute.
41
42
43```ts
44@AnimatableExtend(Text) function animatableFontSize(size: number) {
45  .fontSize(size)
46}
47
48@Entry
49@Component
50struct AnimatablePropertyExample {
51  @State fontSize: number = 20
52  build() {
53    Column() {
54      Text("AnimatableProperty")
55        .animatableFontSize(this.fontSize)
56        .animation({duration: 1000, curve: "ease"})
57      Button("Play")
58        .onClick(() => {
59          this.fontSize = this.fontSize == 20 ? 36 : 20
60        })
61    }.width("100%")
62    .padding(10)
63  }
64}
65```
66![image](figures/animatable-font-size.gif)
67
68
69The following example implements a polyline animation effect.
70
71
72```ts
73class Point {
74  x: number
75  y: number
76
77  constructor(x: number, y: number) {
78    this.x = x
79    this.y = y
80  }
81  plus(rhs: Point): Point {
82    return new Point(this.x + rhs.x, this.y + rhs.y)
83  }
84  subtract(rhs: Point): Point {
85    return new Point(this.x - rhs.x, this.y - rhs.y)
86  }
87  multiply(scale: number): Point {
88    return new Point(this.x * scale, this.y * scale)
89  }
90  equals(rhs: Point): boolean {
91    return this.x === rhs.x && this.y === rhs.y
92  }
93}
94
95class PointVector extends Array<Point> implements AnimatableArithmetic<PointVector> {
96  constructor(value: Array<Point>) {
97    super();
98    value.forEach(p => this.push(p))
99  }
100  plus(rhs: PointVector): PointVector {
101    let result = new PointVector([])
102    const len = Math.min(this.length, rhs.length)
103    for (let i = 0; i < len; i++) {
104      result.push((this as Array<Point>)[i].plus((rhs as Array<Point>)[i]))
105    }
106    return result
107  }
108  subtract(rhs: PointVector): PointVector {
109    let result = new PointVector([])
110    const len = Math.min(this.length, rhs.length)
111    for (let i = 0; i < len; i++) {
112      result.push((this as Array<Point>)[i].subtract((rhs as Array<Point>)[i]))
113    }
114    return result
115  }
116  multiply(scale: number): PointVector {
117    let result = new PointVector([])
118    for (let i = 0; i < this.length; i++) {
119      result.push((this as Array<Point>)[i].multiply(scale))
120    }
121    return result
122  }
123  equals(rhs: PointVector): boolean {
124    if (this.length != rhs.length) {
125      return false
126    }
127    for (let i = 0; i < this.length; i++) {
128      if (!(this as Array<Point>)[i].equals((rhs as Array<Point>)[i])) {
129        return false
130      }
131    }
132    return true
133  }
134  get(): Array<Object[]> {
135    let result: Array<Object[]> = []
136    this.forEach(p => result.push([p.x, p.y]))
137    return result
138  }
139}
140
141@AnimatableExtend(Polyline) function animatablePoints(points: PointVector) {
142  .points(points.get())
143}
144
145@Entry
146@Component
147struct AnimatablePropertyExample {
148  @State points: PointVector = new PointVector([
149    new Point(50, Math.random() * 200),
150    new Point(100, Math.random() * 200),
151    new Point(150, Math.random() * 200),
152    new Point(200, Math.random() * 200),
153    new Point(250, Math.random() * 200),
154  ])
155  build() {
156    Column() {
157      Polyline()
158        .animatablePoints(this.points)
159        .animation({duration: 1000, curve: "ease"})
160        .size({height:220, width:300})
161        .fill(Color.Green)
162        .stroke(Color.Red)
163        .backgroundColor('#eeaacc')
164      Button("Play")
165        .onClick(() => {
166          this.points = new PointVector([
167            new Point(50, Math.random() * 200),
168            new Point(100, Math.random() * 200),
169            new Point(150, Math.random() * 200),
170            new Point(200, Math.random() * 200),
171            new Point(250, Math.random() * 200),
172          ])
173        })
174    }.width("100%")
175    .padding(10)
176  }
177}
178```
179![image](figures/animatable-points.gif)
180