# Spring Curve In a damped spring system corresponding to a damped spring curve (spring curve for short), an object that deviates from the equilibrium position is forced to oscillate due to a reverse force generated by spring deformation; this oscillation is resisted by the damping force. Except for the special case where the damping is 0, the oscillation gradually decays in amplitude towards 0, and the resultant animation curve is naturally continuous. An animation using the spring curve slows down toward the end where the velocity of 0, instead of stopping abruptly. ArkUI provides four types of damped spring curve APIs: - [springMotion](../reference/apis/js-apis-curve.md#curvesspringmotion9): creates a spring animation curve. The animation duration is automatically calculated based on the curve parameters, attribute change values, and initial spring velocity. Manually set animation duration values do not take effect. **springMotion** does not provide any API for setting the velocity, as the velocity is obtained through inheritance. For an attribute, if there is already a springMotion or responsiveSpringMotion animation running, a new spring animation will stop the running animation and inherit the attribute values and velocity of that animation as its initial values. This spring curve API provides default parameters, which you can directly use when appropriate. ```ts function springMotion(response?: number, dampingFraction?: number, overlapDuration?: number): ICurve; ``` - [responsiveSpringMotion](../reference/apis/js-apis-curve.md#curvesresponsivespringmotion9): creates a responsive spring animation curve. It is a special case of **springMotion**, with the only difference in the default values. It is typically used to create an animation with a gesture on the screen. You can use **springMotion** to create an animation for when the user lifts their finger off the screen. The created animation automatically inherits the previous velocity for animation transition. When the **overlapDuration** parameter of the new animation is not **0** and the previous spring animation of the current attribute is not yet complete, **response** and **dampingFracion** transit from the values of the previous animation to that of the new animation within the period specified by **overlapDuration**. ```ts function responsiveSpringMotion(response?: number, dampingFraction?: number, overlapDuration?: number): ICurve; ``` - [interpolatingSpring](../reference/apis/js-apis-curve.md#curvesinterpolatingspring10): creates an interpolating spring curve animated from 0 to 1. It applies to scenarios where the initial animation velocity needs to be specified. The animation duration is automatically calculated, and the manually specified animation duration does not take effect. The actual animation value is calculated based on the curve. Therefore, the velocity should be the normalized speed, which is equal to the absolute speed of the animation attribute change divided by the amount of the animation attribute change. In light of this, this API is not applicable to the scenario where the attribute value of the animation start point is the same as that of the animation end point, since under this scenario, the amount of the animation attribute change is 0, and the normalized speed does not exist. ```ts function interpolatingSpring(velocity: number, mass: number, stiffness: number, damping: number): ICurve; ``` - [springCurve](../reference/apis/js-apis-curve.md#curvesspringcurve9): creates a spring curve with the specified animation duration. This API is almost the same as **interpolatingSpring**. However, for an animation that uses **springCurve**, the physical duration of the curve is mapped to the specified duration, which is equivalent to stretching or compressing the curve on the time axis and violating the original physical rule of the curve. Whenever possible, avoid using this API. ```ts function springCurve(velocity: number, mass: number, stiffness: number, damping: number): ICurve; ``` The following shows a complete example and effect of spring curves. For details about how to connect gestures and animations, see [Animation Smoothing](arkts-animation-smoothing.md). ```ts import curves from '@ohos.curves'; class Spring { public title: string; public subTitle: string; public iCurve: ICurve; constructor(title: string, subTitle: string, iCurve: ICurve) { this.title = title; this.iCurve = iCurve; this.subTitle = subTitle; } } // Spring component @Component struct Motion { @Prop dRotate: number private title: string private subTitle: string private iCurve: ICurve build() { Row() { Column() { Text(this.title) .fontColor(Color.Black) .fontSize(16) Text(this.subTitle) .fontColor(0xcccccc) .fontSize(12) } .width(200) .alignItems(HorizontalAlign.Start) .justifyContent(FlexAlign.Center) .height(100) Stack({ alignContent: Alignment.Top }) { // Circle Column() .width(100) .height(100) .border({ width: 10, color: 0xf56c6c, radius: 50 }) .backgroundColor(Color.White) // Mask layer Column() { Row() .width(100) .height(100) .border({ width: 10, color: 0x909399, radius: 50 }) .backgroundColor(0xf56c6c) } .width(100) .height(50) .clip(true) .rotate({ angle: this.dRotate, centerX: 50, centerY: 50 }) .animation({ curve: this.iCurve, iterations: -1 }) } .width(100) .height(100) } .height(110) .borderWidth({ bottom: 1 }) .borderColor(0xf5f5f5) .margin({ bottom: 5 }) .alignItems(VerticalAlign.Top) } } @Entry @Component export struct SpringDemo { @State dRotate: number = 0; private springs: Spring[] = [ new Spring('springMotion()', '(springMotion(1, 0.25): \n\nCycle: 2; damping: 0.25)', curves.springMotion(1, 0.25)), new Spring('responsiveSpringMotion()', 'responsiveSpringMotion(1, 0.25): \n\nDefault responsive spring curve', curves.responsiveSpringMotion(1, 0.25)), new Spring('interpolatingSpring()', '(interpolatingSpring(10, 1, 228, 30): \n\nInitial velocity: 100; quality: 1; stiffness: 228; damping: 30)', curves.interpolatingSpring(10, 1, 228, 30)), new Spring('springCurve()', '(springCurve(10, 1, 228, 30): \n\nInitial velocity: 100; quality: 1; stiffness: 228; damping: 30)', curves.springCurve(10, 1, 228, 30)) ]; build() { Column() { ForEach(this.springs, (item: Spring) => { Motion({ title: item.title, subTitle: item.subTitle, iCurve: item.iCurve, dRotate: this.dRotate }) }) } .justifyContent(FlexAlign.Center) .width('100%') .height(437) .margin({ top: 20 }) .onClick(() => { this.dRotate = 360; }) } } ``` ![en-us_image_0000001649089041](figures/en-us_image_0000001649089041.gif)