@AnimatableExtend装饰器用于自定义可动画的属性方法,在这个属性方法中修改组件不可动画的属性。在动画执行过程时,通过逐帧回调函数修改不可动画属性值,让不可动画属性也能实现动画效果。
说明:
该装饰器从API Version 10开始支持。后续版本如有新增内容,则采用上角标单独标记该内容的起始版本。
- @AnimatableExtend(UIComponentName) function functionName(value: typeName) {
- .propertyName(value)
- }
对复杂数据类型做动画,需要实现AnimtableArithmetic
| 名称 | 入参类型 | 返回值类型 | 说明 |
| plus | AnimtableArithmetic | AnimtableArithmetic | 加法函数 |
| subtract | AnimtableArithmetic | AnimtableArithmetic | 减法函数 |
| multiply | number | AnimtableArithmetic | 乘法函数 |
| equals | AnimtableArithmetic | boolean | 相等判断函数 |
以下示例实现字体大小的动画效果。
- @AnimatableExtend(Text) function animatableFontSize(size: number) {
- .fontSize(size)
- }
-
- @Entry
- @Component
- struct AnimatablePropertyExample {
- @State fontSize: number = 20
- build() {
- Column() {
- Text("AnimatableProperty")
- .animatableFontSize(this.fontSize)
- .animation({duration: 1000, curve: "ease"})
- Button("Play")
- .onClick(() => {
- this.fontSize = this.fontSize == 20 ? 36 : 20
- })
- }.width("100%")
- .padding(10)
- }
- }

以下示例实现折线的动画效果。
- class Point {
- x: number
- y: number
-
- constructor(x: number, y: number) {
- this.x = x
- this.y = y
- }
- plus(rhs: Point): Point {
- return new Point(this.x + rhs.x, this.y + rhs.y)
- }
- subtract(rhs: Point): Point {
- return new Point(this.x - rhs.x, this.y - rhs.y)
- }
- multiply(scale: number): Point {
- return new Point(this.x * scale, this.y * scale)
- }
- equals(rhs: Point): boolean {
- return this.x === rhs.x && this.y === rhs.y
- }
- }
-
- class PointVector extends Array<Point> implements AnimatableArithmetic<PointVector> {
- constructor(value: Array<Point>) {
- super();
- value.forEach(p => this.push(p))
- }
- plus(rhs: PointVector): PointVector {
- let result = new PointVector([])
- const len = Math.min(this.length, rhs.length)
- for (let i = 0; i < len; i++) {
- result.push((this as Array<Point>)[i].plus((rhs as Array<Point>)[i]))
- }
- return result
- }
- subtract(rhs: PointVector): PointVector {
- let result = new PointVector([])
- const len = Math.min(this.length, rhs.length)
- for (let i = 0; i < len; i++) {
- result.push((this as Array<Point>)[i].subtract((rhs as Array<Point>)[i]))
- }
- return result
- }
- multiply(scale: number): PointVector {
- let result = new PointVector([])
- for (let i = 0; i < this.length; i++) {
- result.push((this as Array<Point>)[i].multiply(scale))
- }
- return result
- }
- equals(rhs: PointVector): boolean {
- if (this.length != rhs.length) {
- return false
- }
- for (let i = 0; i < this.length; i++) {
- if (!(this as Array<Point>)[i].equals((rhs as Array<Point>)[i])) {
- return false
- }
- }
- return true
- }
- get(): Array<Object[]> {
- let result: Array<Object[]> = []
- this.forEach(p => result.push([p.x, p.y]))
- return result
- }
- }
-
- @AnimatableExtend(Polyline) function animatablePoints(points: PointVector) {
- .points(points.get())
- }
-
- @Entry
- @Component
- struct AnimatablePropertyExample {
- @State points: PointVector = new PointVector([
- new Point(50, Math.random() * 200),
- new Point(100, Math.random() * 200),
- new Point(150, Math.random() * 200),
- new Point(200, Math.random() * 200),
- new Point(250, Math.random() * 200),
- ])
- build() {
- Column() {
- Polyline()
- .animatablePoints(this.points)
- .animation({duration: 1000, curve: "ease"})
- .size({height:220, width:300})
- .fill(Color.Green)
- .stroke(Color.Red)
- .backgroundColor('#eeaacc')
- Button("Play")
- .onClick(() => {
- this.points = new PointVector([
- new Point(50, Math.random() * 200),
- new Point(100, Math.random() * 200),
- new Point(150, Math.random() * 200),
- new Point(200, Math.random() * 200),
- new Point(250, Math.random() * 200),
- ])
- })
- }.width("100%")
- .padding(10)
- }
- }
