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 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 180