HarmonyOS 6 @AnimatableExtend 自定义类型折线动画效果使用文档
文章目录动画效果代码核心原理自定义类型折线动画实现流程1. 定义基础坐标点类型 Point2. 自定义可动画集合 PointVector核心3. 使用 AnimatableExtend 扩展组件4. 状态驱动动画核心 API / 接口说明1. AnimatableArithmeticT2. AnimatableExtend(组件名)3. animation({ duration, curve })代码功能解析1. Point 类2. PointVector 类3. animatablePoints 扩展函数4. 页面组件总结动画效果点击 Play 按钮后折线的所有顶点坐标从旧位置自动平滑过渡到新位置形成流畅的形变动画而非瞬间切换。代码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实现了AnimatableArithmeticT接口 class PointVector extends ArrayPoint implements AnimatableArithmeticPointVector { constructor(value: ArrayPoint) { 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 ArrayPoint)[i].plus((rhs as ArrayPoint)[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 ArrayPoint)[i].subtract((rhs as ArrayPoint)[i])); } return result; } multiply(scale: number): PointVector { let result new PointVector([]); for (let i 0; i this.length; i) { result.push((this as ArrayPoint)[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 ArrayPoint)[i].equals((rhs as ArrayPoint)[i])) { return false; } } return true; } get(): ArrayObject[] { let result: ArrayObject[] []; 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: Curve.Ease })// 设置动画参数 .size({ height: 220, width: 300 }) .fill(Color.Green) .stroke(Color.Red) .backgroundColor(#eeaacc) Button(Play) .onClick(() { // points是实现了可动画协议的数据类型points在动画过程中可按照定义的运算规则、动画参数从之前的PointVector变为新的PointVector数据产生每一帧的PointVector数据进而产生动画 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) } }运行效果如图点击按钮图形变化核心原理自定义类型折线动画实现流程整个动画基于「自定义可动画数据类型 组件扩展 状态驱动」实现1. 定义基础坐标点类型 Point提供坐标点的加减乘运算是动画插值计算的基础plus坐标相加subtract坐标相减multiply缩放动画插值核心equals判断坐标是否相等2. 自定义可动画集合 PointVector核心继承ArrayPoint实现 AnimatableArithmetic 接口让框架识别该类型为可动画类型自动对集合内所有顶点逐帧做插值运算输出平滑过渡的顶点坐标提供get()方法将顶点转为组件支持的格式3. 使用 AnimatableExtend 扩展组件AnimatableExtend(Polyline) function animatablePoints(points: PointVector) { .points(points.get()) }给Polyline扩展可动画方法animatablePoints动画每帧自动调用更新折线顶点4. 状态驱动动画State points: PointVector ...状态变量更新 → 触发框架自动执行逐帧插值运算平滑从旧顶点集合 → 过渡到新顶点集合配合.animation()控制时长与曲线核心 API / 接口说明1. AnimatableArithmetic自定义类型必须实现的可动画标准接口interfaceAnimatableArithmeticT{plus(rhs:T):T;subtract(rhs:T):T;multiply(scale:number):T;equals(rhs:T):boolean;}作用框架通过这4个方法完成逐帧插值计算。2. AnimatableExtend(组件名)装饰器将自定义函数扩展为目标组件的可动画属性方法。3. animation({ duration, curve })配置动画参数duration: 1000动画时长 1000mscurve: Curve.Ease先加速后减速的平滑曲线代码功能解析1. Point 类坐标点基础运算类为顶点平滑过渡提供数学支持。2. PointVector 类实现可动画接口让点集合可动画逐帧对所有顶点做插值运算输出每一帧的顶点坐标get()方法将数据转为 Polyline 所需格式3. animatablePoints 扩展函数扩展 Polyline 组件接收 PointVector 并设置到折线顶点逐帧更新形成形变动画4. 页面组件State 存储可动画顶点数据Polyline 使用自定义动画属性点击按钮随机生成新坐标 → 触发平滑动画总结自定义类型必须实现 AnimatableArithmetic 接口接口四个方法plus/subtract/multiply/equals必须全部实现扩展函数必须用AnimatableExtend装饰且定义在全局数据更新必须通过State变量驱动必须配合.animation()属性才能产生动画如果这篇文章对你有帮助欢迎点赞、收藏、关注你的支持是持续创作的动力