1# \@AnimatableExtend装饰器:定义可动画属性 2 3@AnimatableExtend装饰器用于自定义可动画的属性方法,在这个属性方法中修改组件不可动画的属性。在动画执行过程时,通过逐帧回调函数修改不可动画属性值,让不可动画属性也能实现动画效果。 4 5- 可动画属性:如果一个属性方法在animation属性前调用,改变这个属性的值可以生效animation属性的动画效果,这个属性称为可动画属性。比如height、width、backgroundColor、translate属性,Text组件的fontSize属性等。 6 7- 不可动画属性:如果一个属性方法在animation属性前调用,改变这个属性的值不能生效animation属性的动画效果,这个属性称为不可动画属性。比如Polyline组件的points属性等。 8 9> **说明:** 10> 11> 该装饰器从API Version 10开始支持。后续版本如有新增内容,则采用上角标单独标记该内容的起始版本。 12 13## 装饰器使用说明 14 15 16### 语法 17 18 19```ts 20@AnimatableExtend(UIComponentName) function functionName(value: typeName) { 21 .propertyName(value) 22} 23``` 24 25- \@AnimatableExtend仅支持定义在全局,不支持在组件内部定义。 26- \@AnimatableExtend定义的函数参数类型必须为number类型或者实现 AnimtableArithmetic\<T\>接口的自定义类型。 27- \@AnimatableExtend定义的函数体内只能调用\@AnimatableExtend括号内组件的属性方法。 28 29### AnimtableArithmetic\<T\>接口说明 30对复杂数据类型做动画,需要实现AnimtableArithmetic\<T\>接口中加法、减法、乘法和判断相等函数。 31| 名称 | 入参类型 | 返回值类型 | 说明 32| -------- | -------- |-------- |-------- | 33| plus | AnimtableArithmetic\<T\> | AnimtableArithmetic\<T\> | 加法函数 | 34| subtract | AnimtableArithmetic\<T\> | AnimtableArithmetic\<T\> | 减法函数 | 35| multiply | number | AnimtableArithmetic\<T\> | 乘法函数 | 36| equals | AnimtableArithmetic\<T\> | boolean | 相等判断函数 | 37 38## 使用场景 39 40以下示例实现字体大小的动画效果。 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 69以下示例实现折线的动画效果。 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