diff --git a/zh-cn/application-dev/Readme-CN.md b/zh-cn/application-dev/Readme-CN.md index 30c708b75f8b6ad24f1c1e42ba4ce84fe441066d..82f29538e3605416c6b54620a1272e2f1b639bdc 100644 --- a/zh-cn/application-dev/Readme-CN.md +++ b/zh-cn/application-dev/Readme-CN.md @@ -50,6 +50,7 @@ - [\@BuilderParam装饰器:引用\@Builder函数](quick-start/arkts-builderparam.md) - [\@Styles装饰器:定义组件重用样式](quick-start/arkts-style.md) - [\@Extend装饰器:定义扩展组件样式](quick-start/arkts-extend.md) + - [\@AnimatableExtend装饰器:定义可动画属性](quick-start/arkts-animatable-extend.md) - [stateStyles:多态样式](quick-start/arkts-statestyles.md) - 状态管理 - [状态管理概述](quick-start/arkts-state-management-overview.md) diff --git a/zh-cn/application-dev/quick-start/arkts-animatable-extend.md b/zh-cn/application-dev/quick-start/arkts-animatable-extend.md new file mode 100644 index 0000000000000000000000000000000000000000..77b102c683ae88ef007a173b337b5d9e6aea1257 --- /dev/null +++ b/zh-cn/application-dev/quick-start/arkts-animatable-extend.md @@ -0,0 +1,179 @@ +# \@AnimatableExtend:定义可动画属性 + +@AnimatableExtend装饰器用于自定义可动画的属性方法,在这个属性方法中修改组件不可动画的属性。在动画执行过程时,通过逐帧回调函数修改不可动画属性值,让不可动画属性也能实现动画效果。 + +- 可动画属性:如果一个属性方法在animation属性前调用,改变这个属性的值可以生效animation属性的动画效果,这个属性称为可动画属性。比如height、width、backgroundColor、translate等。 + +- 不可动画属性:如果一个属性方法在animation属性前调用,改变这个属性的值不能生效animation属性的动画效果,这个属性称为不可动画属性。比如Text组件的fontSize属性、Ployline组件的points属性等。 + +> **说明:** +> +> 该装饰器从API Version 10开始支持。后续版本如有新增内容,则采用上角标单独标记该内容的起始版本。 + +## 装饰器使用说明 + + +### 语法 + + +```ts +@AnimatableExtend(UIComponentName) function functionName(value: typeName) { + .propertyName(value) +} +``` + +- \@AnimatableExtend仅支持定义在全局,不支持在组件内部定义。 +- \@AnimatableExtend定义的函数参数类型必须为number类型或者实现 AnimtableArithmetic\接口的自定义类型。 +- \@AnimatableExtend定义的函数体内只能调用\@AnimatableExtend括号内组件的属性方法。 + +### AnimtableArithmetic\接口说明 +对复杂数据类型做动画,需要实现AnimtableArithmetic\接口中加法、减法、乘法和判断相等函数。 +| 名称 | 入参类型 | 返回值类型 | 说明 +| -------- | -------- |-------- |-------- | +| plus | AnimtableArithmetic\ | AnimtableArithmetic\ | 加法函数 | +| subtract | AnimtableArithmetic\ | AnimtableArithmetic\ | 减法函数 | +| multiply | number | AnimtableArithmetic\ | 乘法函数 | +| equals | AnimtableArithmetic\ | boolean | 相等判断函数 | + +## 使用场景 + +以下示例实现字体大小的动画效果。 + + +```ts +@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) + } +} +``` +![image](figures/animatable-font-size.gif) + + +以下示例实现折线的动画效果。 + + +```ts +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 implements AnimatableArithmetic { + constructor(value: Array) { + 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[i].plus(rhs[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[i].subtract(rhs[i])) + } + return result + } + multiply(scale: number): PointVector { + let result = new PointVector([]) + for (let i = 0; i < this.length; i++) { + result.push(this[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[i].equals(rhs[i])) { + return false + } + } + return true + } + get():Array<[x: number, y: number]> { + let result = [] + 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) + } +} +``` +![image](figures/animatable-points.gif) \ No newline at end of file diff --git a/zh-cn/application-dev/quick-start/figures/animatable-font-size.gif b/zh-cn/application-dev/quick-start/figures/animatable-font-size.gif new file mode 100644 index 0000000000000000000000000000000000000000..b127a59f8899e20aa4b827ad3b2101b0d08d1b8d Binary files /dev/null and b/zh-cn/application-dev/quick-start/figures/animatable-font-size.gif differ diff --git a/zh-cn/application-dev/quick-start/figures/animatable-points.gif b/zh-cn/application-dev/quick-start/figures/animatable-points.gif new file mode 100644 index 0000000000000000000000000000000000000000..64092e50a4c3869c61f09347048eeb041a46dd9d Binary files /dev/null and b/zh-cn/application-dev/quick-start/figures/animatable-points.gif differ