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> 从API version 11开始,该装饰器支持在原子化服务中使用。 14 15## 装饰器使用说明 16 17 18### 语法 19 20 21```ts 22@AnimatableExtend(UIComponentName) function functionName(value: typeName) { 23 .propertyName(value) 24} 25``` 26 27- \@AnimatableExtend仅支持定义在全局,不支持在组件内部定义。 28- \@AnimatableExtend定义的函数参数类型必须为number类型或者实现 AnimatableArithmetic\<T\>接口的自定义类型。 29- \@AnimatableExtend定义的函数体内只能调用\@AnimatableExtend括号内组件的属性方法。 30 31### AnimatableArithmetic\<T\>接口说明 32对复杂数据类型做动画,需要实现AnimatableArithmetic\<T\>接口中加法、减法、乘法和判断相等函数。 33| 名称 | 入参类型 | 返回值类型 | 说明 34| -------- | -------- |-------- |-------- | 35| plus | AnimatableArithmetic\<T\> | AnimatableArithmetic\<T\> | 加法函数 | 36| subtract | AnimatableArithmetic\<T\> | AnimatableArithmetic\<T\> | 减法函数 | 37| multiply | number | AnimatableArithmetic\<T\> | 乘法函数 | 38| equals | AnimatableArithmetic\<T\> | boolean | 相等判断函数 | 39 40## 使用场景 41 42以下示例通过改变Text组件宽度实现逐帧布局的效果。 43 44 45```ts 46@AnimatableExtend(Text) 47function animatableWidth(width: number) { 48 .width(width) 49} 50 51@Entry 52@Component 53struct AnimatablePropertyExample { 54 @State textWidth: number = 80; 55 56 build() { 57 Column() { 58 Text("AnimatableProperty") 59 .animatableWidth(this.textWidth) 60 .animation({ duration: 2000, curve: Curve.Ease }) 61 Button("Play") 62 .onClick(() => { 63 this.textWidth = this.textWidth == 80 ? 160 : 80; 64 }) 65 }.width("100%") 66 .padding(10) 67 } 68} 69``` 70 71 72 73以下示例实现折线的动画效果。 74 75 76```ts 77class Point { 78 x: number 79 y: number 80 81 constructor(x: number, y: number) { 82 this.x = x 83 this.y = y 84 } 85 plus(rhs: Point): Point { 86 return new Point(this.x + rhs.x, this.y + rhs.y) 87 } 88 subtract(rhs: Point): Point { 89 return new Point(this.x - rhs.x, this.y - rhs.y) 90 } 91 multiply(scale: number): Point { 92 return new Point(this.x * scale, this.y * scale) 93 } 94 equals(rhs: Point): boolean { 95 return this.x === rhs.x && this.y === rhs.y 96 } 97} 98 99class PointVector extends Array<Point> implements AnimatableArithmetic<PointVector> { 100 constructor(value: Array<Point>) { 101 super(); 102 value.forEach(p => this.push(p)) 103 } 104 plus(rhs: PointVector): PointVector { 105 let result = new PointVector([]) 106 const len = Math.min(this.length, rhs.length) 107 for (let i = 0; i < len; i++) { 108 result.push((this as Array<Point>)[i].plus((rhs as Array<Point>)[i])) 109 } 110 return result 111 } 112 subtract(rhs: PointVector): PointVector { 113 let result = new PointVector([]) 114 const len = Math.min(this.length, rhs.length) 115 for (let i = 0; i < len; i++) { 116 result.push((this as Array<Point>)[i].subtract((rhs as Array<Point>)[i])) 117 } 118 return result 119 } 120 multiply(scale: number): PointVector { 121 let result = new PointVector([]) 122 for (let i = 0; i < this.length; i++) { 123 result.push((this as Array<Point>)[i].multiply(scale)) 124 } 125 return result 126 } 127 equals(rhs: PointVector): boolean { 128 if (this.length != rhs.length) { 129 return false 130 } 131 for (let i = 0; i < this.length; i++) { 132 if (!(this as Array<Point>)[i].equals((rhs as Array<Point>)[i])) { 133 return false 134 } 135 } 136 return true 137 } 138 get(): Array<Object[]> { 139 let result: Array<Object[]> = [] 140 this.forEach(p => result.push([p.x, p.y])) 141 return result 142 } 143} 144 145@AnimatableExtend(Polyline) function animatablePoints(points: PointVector) { 146 .points(points.get()) 147} 148 149@Entry 150@Component 151struct AnimatablePropertyExample { 152 @State points: PointVector = new PointVector([ 153 new Point(50, Math.random() * 200), 154 new Point(100, Math.random() * 200), 155 new Point(150, Math.random() * 200), 156 new Point(200, Math.random() * 200), 157 new Point(250, Math.random() * 200), 158 ]) 159 build() { 160 Column() { 161 Polyline() 162 .animatablePoints(this.points) 163 .animation({duration: 1000, curve: Curve.Ease}) 164 .size({height:220, width:300}) 165 .fill(Color.Green) 166 .stroke(Color.Red) 167 .backgroundColor('#eeaacc') 168 Button("Play") 169 .onClick(() => { 170 this.points = new PointVector([ 171 new Point(50, Math.random() * 200), 172 new Point(100, Math.random() * 200), 173 new Point(150, Math.random() * 200), 174 new Point(200, Math.random() * 200), 175 new Point(250, Math.random() * 200), 176 ]) 177 }) 178 }.width("100%") 179 .padding(10) 180 } 181} 182``` 183