HarmonyOS:@AnimatableExtend 装饰器自学指南

在最近的项目开发中,我遇到了需要实现复杂动画效果的需求。在探索解决方案的过程中,我发现了 ​​@AnimatableExtend​​​ 装饰器,它为实现动画效果提供了一种非常灵活且强大的方式。然而,在学习这个装饰器的过程中,我发现相关的资料并不是特别丰富,而且很多资料都缺乏系统性的讲解。因此,我决定写这篇博客,将自己的学习经验和理解分享出来,希望能帮助更多的开发者快速掌握 ​​@AnimatableExtend​​ 装饰器的使用。

1. ​​@AnimatableExtend​​ 装饰器概述

​@AnimatableExtend​​ 装饰器从 API Version 10 开始支持,为动画效果的实现提供了一种便捷的方式。从 API version 11 开始,它支持在元服务中使用。这个装饰器允许我们自定义动画属性,使得我们可以对不同类型的数据进行动画处理。

1.1 装饰器使用规则

  • 定义位置​@AnimatableExtend​ 仅支持定义在全局,不支持在组件内部定义。
  • 参数类型​@AnimatableExtend​ 定义的函数参数类型必须为 ​number​ 类型或者实现 ​AnimatableArithmetic<T>​ 接口的自定义类型。
  • 函数体限制​@AnimatableExtend​ 定义的函数体内只能调用 ​@AnimatableExtend​ 括号内组件的属性方法。

1.2 ​​AnimatableArithmetic<T>​​ 接口说明

​AnimatableArithmetic<T>​​​ 接口定义了非 ​​number​​​ 数据类型的动画运算规则。对于非 ​​number​​ 类型的数据(如数组、结构体、颜色等)做动画,需要实现该接口中的加法、减法、乘法和判断相等函数,使得该数据能参与动画的插值运算和识别该数据是否发生改变。

名称 入参类型 返回值类型 说明
plus AnimatableArithmetic AnimatableArithmetic 定义该数据类型的加法运算规则
subtract AnimatableArithmetic AnimatableArithmetic 定义该数据类型的减法运算规则
multiply number AnimatableArithmetic 定义该数据类型的乘法运算规则
equals AnimatableArithmetic boolean 定义该数据类型的相等判断规则

2. 使用场景示例

2.1 改变 Text 组件宽度实现逐帧布局效果

下面的示例通过改变 ​​Text​​ 组件的宽度实现逐帧布局的效果。

less 复制代码
@AnimatableExtend(Text)
function animatableWidth(width: number) {
  .width(width)
}

@Entry
@Component
struct AnimatablePropertyExample {
  @State textWidth: number = 100;

  build() {
    Column() {
      Text("AnimatableProperty")
        .animatableWidth(this.textWidth)
        .animation({ duration: 3000, curve: Curve.EaseInOut })
      Button("Play")
        .onClick(() => {
          this.textWidth = this.textWidth == 100 ? 200 : 100;
        })
    }.width("100%")
    .padding(20)
  }
}

在这个示例中,我们定义了一个 ​​animatableWidth​​​ 函数,通过 ​​@AnimatableExtend​​​ 装饰器将其应用到 ​​Text​​​ 组件上。点击按钮时,​​textWidth​​ 的值会在 100 和 200 之间切换,从而触发动画效果。

2.2 实现折线的动画效果

为了实现折线的动画效果,我们需要定义一个自定义类型 ​​Point​​​ 和 ​​PointVector​​​,并让 ​​PointVector​​​ 实现 ​​AnimatableArithmetic<T>​​ 接口。

kotlin 复制代码
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
  }
}

// PointVector实现了AnimatableArithmetic<T>接口
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(30, Math.random() * 250),
    new Point(80, Math.random() * 250),
    new Point(130, Math.random() * 250),
    new Point(180, Math.random() * 250),
    new Point(230, Math.random() * 250),
  ])

  build() {
    Column() {
      Polyline()
        .animatablePoints(this.points)
        .animation({ duration: 1500, curve: Curve.EaseOut })// 设置动画参数
        .size({ height: 250, width: 350 })
        .fill(Color.Blue)
        .stroke(Color.Yellow)
        .backgroundColor('#aaccff')
      Button("Play")
        .onClick(() => {
          // points是实现了可动画协议的数据类型,points在动画过程中可按照定义的运算规则、动画参数从之前的PointVector变为新的PointVector数据,产生每一帧的PointVector数据,进而产生动画
          this.points = new PointVector([
            new Point(30, Math.random() * 250),
            new Point(80, Math.random() * 250),
            new Point(130, Math.random() * 250),
            new Point(180, Math.random() * 250),
            new Point(230, Math.random() * 250),
          ])
        })
    }.width("100%")
    .padding(20)
  }
}

在这个示例中,我们定义了 ​​Point​​​ 类表示二维平面上的点,​​PointVector​​​ 类表示点的数组。通过实现 ​​AnimatableArithmetic<T>​​​ 接口,我们为 ​​PointVector​​​ 定义了加法、减法、乘法和相等判断规则。然后,我们使用 ​​@AnimatableExtend​​​ 装饰器将 ​​animatablePoints​​​ 函数应用到 ​​Polyline​​ 组件上,点击按钮时,折线的顶点位置会随机变化,从而实现动画效果。

3. 总结

​@AnimatableExtend​​​ 装饰器为实现复杂动画效果提供了一种强大而灵活的方式。通过自定义动画属性和实现 ​​AnimatableArithmetic<T>​​​ 接口,我们可以对不同类型的数据进行动画处理。在实际开发中,我们可以根据具体需求灵活运用这个装饰器,实现各种炫酷的动画效果。希望这篇博客能帮助你快速掌握 ​​@AnimatableExtend​​ 装饰器的使用,让你的应用更加生动有趣。

通过以上的学习和实践,你可以逐步掌握 ​​@AnimatableExtend​​ 装饰器的使用方法,并且在实际项目中灵活运用,为用户带来更加丰富的动画体验。

相关推荐
zzialx22 分钟前
HarmonyOS:基于axios实现文件的下载以及下载进度的监听
harmonyos·鸿蒙
IT乐手1 小时前
3.5、HarmonyOS Next 文本显示(Text/Span)
harmonyos
IT乐手1 小时前
3.6、HarmonyOS Next 文本输入(TextInput/TextArea)
harmonyos
Georgewu1 小时前
【HarmonyOS Next】鸿蒙应用弹框和提示气泡详解(二)之浮层(OverlayManager),半模态页面(bindSheet),全模态页面(bindC
前端·华为·harmonyos
BensionLZ3 小时前
HO与OH差异之Navigation
harmonyos
CV工程师丁Sir3 小时前
《HarmonyOS Next状态栏动画实现案例与代码解析》
华为·harmonyos·harmonyos next
ChinaDragonDreamer4 小时前
HarmonyOS:通过键值型数据库实现数据持久化
harmonyos·鸿蒙
二川bro5 小时前
HarmonyOS NEXT(十) :系统集成与调试
华为·wpf·harmonyos
李游Leo7 小时前
HarmonyOS 之 @Require 装饰器自学指南
harmonyos
SameX8 小时前
HarmonyOS Next ohpm-repo 数据存储安全与多实例高可用部署
前端·harmonyos