• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# 弹簧曲线
2<!--Kit: ArkUI-->
3<!--Subsystem: ArkUI-->
4<!--Owner: @CCFFWW-->
5<!--Designer: @yangfan229-->
6<!--Tester: @lxl007-->
7<!--Adviser: @HelloCrease-->
8
9
10阻尼弹簧曲线(以下简称弹簧曲线)对应的阻尼弹簧系统中,偏离平衡位置的物体一方面受到弹簧形变产生的反向作用力,被迫发生振动。另一方面,阻尼的存在为物体振动提供阻力。除阻尼为0的特殊情况,物体在振动过程中振幅不断减小,且最终趋于0,其轨迹对应的动画曲线自然连续。
11
12
13采用弹簧曲线的动画在达终点时动画速度为0,不会产生动画“戛然而止”的观感,以避免影响用户体验。
14
15
16ArkUI提供了四种阻尼弹簧曲线接口。
17
18
19- [curves.springMotion](../reference/apis-arkui/js-apis-curve.md#curvesspringmotion9):创建弹性动画,动画时长由曲线参数、属性变化值大小和弹簧初速度自动计算,开发者指定的动画时长不生效。
20    springMotion不提供速度设置接口,速度通过继承获得,无需开发者指定。对于某个属性,如果当前存在正在运行的springMotion或者responsiveSpringMotion类型动画,新创建的弹簧动画将停止正在运行的动画,并继承其当前时刻的动画属性值和速度作为新建动画的初始状态。此外,接口提供默认参数,便于开发者直接使用。
21
22  ```ts
23  function springMotion(response?: number, dampingFraction?: number, overlapDuration?: number): ICurve;
24  ```
25
26
27- [curves.responsiveSpringMotion](../reference/apis-arkui/js-apis-curve.md#curvesresponsivespringmotion9):是springMotion动画的一种特例,仅默认参数不同。一般用于跟手做成动画的场景,离手时可用springMotion创建动画,此时离手阶段动画将自动继承跟手阶段动画速度,完成动画衔接。
28  当新动画的overlapDuration参数不为0,且当前属性的上一个springMotion动画还未结束时,response和dampingFraction将在overlapDuration指定的时间内,从旧动画的参数值过渡到新动画的参数值。
29
30
31  ```ts
32  function responsiveSpringMotion(response?: number, dampingFraction?: number, overlapDuration?: number): ICurve;
33  ```
34
35
36- [curves.interpolatingSpring](../reference/apis-arkui/js-apis-curve.md#curvesinterpolatingspring10):适合于需要指定初速度的动效场景,动画时长同样由接口参数自动计算,开发者在动画接口中指定的时长不生效。
37  曲线接口提供速度入参,且由于接口对应一条从0到1的阻尼弹簧曲线,实际动画值根据曲线进行插值计算。所以速度也应该为归一化速度,其值等于动画属性改变的绝对速度除以动画属性改变量。因此不适合于动画起点属性值和终点属性值相同的场景,此时动画属性改变量为0,归一化速度不存在。
38
39
40  ```ts
41  function interpolatingSpring(velocity: number, mass: number, stiffness: number, damping: number): ICurve;
42  ```
43
44
45- [curves.springCurve](../reference/apis-arkui/js-apis-curve.md#curvesspringcurve9):适合于需要直接指定动画时长的场景。springCurve接口与interpolatingSpring接口几乎一致,但是对于采用springCurve的动画,会将曲线的物理时长映射到指定的时长,相当于在时间轴上拉伸或压缩曲线,破坏曲线原本的物理规律,因此不建议开发者使用。
46
47  ```ts
48  function springCurve(velocity: number, mass: number, stiffness: number, damping: number): ICurve;
49  ```
50
51
52关于弹簧曲线完整的使用示例和参考效果如下,开发者也可参考[动画衔接](arkts-animation-smoothing.md),掌握使用responsiveSpringMotion和springMotion进行手势和动画之间的衔接。
53
54
55弹簧曲线的示例代码和效果如下。
56
57
58
59```ts
60import { curves } from '@kit.ArkUI';
61
62class Spring {
63  public title: string;
64  public subTitle: string;
65  public iCurve: ICurve;
66
67  constructor(title: string, subTitle: string, iCurve: ICurve) {
68    this.title = title;
69    this.iCurve = iCurve;
70    this.subTitle = subTitle;
71  }
72}
73
74// 弹簧组件
75@Component
76struct Motion {
77  @Prop dRotate: number = 0
78  private title: string = ""
79  private subTitle: string = ""
80  private iCurve: ICurve | undefined = undefined
81
82  build() {
83    Column() {
84      Circle()
85        .translate({ y: this.dRotate })
86        .animation({ curve: this.iCurve, iterations: -1 })
87        .foregroundColor('#317AF7')
88        .width(30)
89        .height(30)
90
91      Column() {
92        Text(this.title)
93          .fontColor(Color.Black)
94          .fontSize(10).height(30)
95        Text(this.subTitle)
96          .fontColor(0xcccccc)
97          .fontSize(10).width(50)
98      }
99      .borderWidth({ top: 1 })
100      .borderColor(0xf5f5f5)
101      .width(80)
102      .alignItems(HorizontalAlign.Center)
103      .height(100)
104
105    }
106    .height(110)
107    .margin({ bottom: 5 })
108    .alignItems(HorizontalAlign.Center)
109  }
110}
111
112@Entry
113@Component
114export struct SpringCurve {
115  @State dRotate: number = 0;
116  private springs: Spring[] = [
117    new Spring('springMotion', '周期1, 阻尼0.25', curves.springMotion(1, 0.25)),
118    new Spring('responsive' + '\n' + 'SpringMotion', '弹性跟手曲线', curves.responsiveSpringMotion(1, 0.25)),
119    new Spring('interpolating' + '\n' + 'Spring', '初始速度10,质量1, 刚度228, 阻尼30',
120      curves.interpolatingSpring(10, 1, 228, 30)),
121    new Spring('springCurve', '初始速度10, 质量1, 刚度228, 阻尼30', curves.springCurve(10, 1, 228, 30))
122  ];
123
124  build() {
125    Row() {
126      ForEach(this.springs, (item: Spring) => {
127        Motion({
128          title: item.title,
129          subTitle: item.subTitle,
130          iCurve: item.iCurve,
131          dRotate: this.dRotate
132        })
133      })
134    }
135    .justifyContent(FlexAlign.Center)
136    .alignItems(VerticalAlign.Bottom)
137    .width('100%')
138    .height(437)
139    .margin({ top: 20 })
140    .onClick(() => {
141      this.dRotate = -50;
142    })
143  }
144}
145```
146
147
148
149![zh-cn_image_0000001649089041](figures/spring_curve.gif)
150
151