• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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![image](figures/AnimatableProperty.gif)
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![image](figures/animatable-points.gif)