1e41f4b71Sopenharmony_ci# Animation Smoothing
2e41f4b71Sopenharmony_ci
3e41f4b71Sopenharmony_ci
4e41f4b71Sopenharmony_ciWhen running animations, the UI is also interacting with users in real time. It must respond immediately to changes in user behavior. For example, if the user swipes up to exit in the midst of an application launch process, the UI should immediately transit from the startup animation to the exit animation, rather than finishing the startup animation before exiting. In the scenario where the animation triggered when the user lifts their fingers off the screen, the initial velocity of the animation must inherit the gesture speed, so as to avoid pauses caused by speed disconnection. For the preceding and similar scenarios, the system provides efficient APIs for smoothing between animations and between animations and gestures.
5e41f4b71Sopenharmony_ci
6e41f4b71Sopenharmony_ciAssume that there is a running animation for an animatable property. If the end value of the property changes due to an operation on the UI, you can create a new animation for it, by changing the property value in the [animateTo](../reference/apis-arkui/arkui-ts/ts-explicit-animation.md) closure or by changing the input parameter value of the [animation](../reference/apis-arkui/arkui-ts/ts-animatorproperty.md) API. The system then automatically connects the previous animation with the new animation.
7e41f4b71Sopenharmony_ci
8e41f4b71Sopenharmony_ciThe following is an example: By clicking **click**, you change the **scale** property of the red square. When you click **click** repeatedly, the end value of the **scale** property changes continuously, and the current animation smoothly moves towards the new end value of the **scale** property.
9e41f4b71Sopenharmony_ci
10e41f4b71Sopenharmony_ci```ts
11e41f4b71Sopenharmony_ciimport { curves } from '@kit.ArkUI';
12e41f4b71Sopenharmony_ciclass SetSlt{
13e41f4b71Sopenharmony_ci  isAnimation:boolean = true
14e41f4b71Sopenharmony_ci  set():void{
15e41f4b71Sopenharmony_ci    this.isAnimation = !this.isAnimation;
16e41f4b71Sopenharmony_ci  }
17e41f4b71Sopenharmony_ci}
18e41f4b71Sopenharmony_ci@Entry
19e41f4b71Sopenharmony_ci@Component
20e41f4b71Sopenharmony_cistruct AnimationToAnimationDemo {
21e41f4b71Sopenharmony_ci// Step 1: Declare the related state variable.
22e41f4b71Sopenharmony_ci  @State SetAnimation: SetSlt = new SetSlt();
23e41f4b71Sopenharmony_ci
24e41f4b71Sopenharmony_ci  build() {
25e41f4b71Sopenharmony_ci    Column() {
26e41f4b71Sopenharmony_ci      Text('ArkUI')
27e41f4b71Sopenharmony_ci        .fontWeight(FontWeight.Bold)
28e41f4b71Sopenharmony_ci        .fontSize(12)
29e41f4b71Sopenharmony_ci        .fontColor(Color.White)
30e41f4b71Sopenharmony_ci        .textAlign(TextAlign.Center)
31e41f4b71Sopenharmony_ci        .borderRadius(10)
32e41f4b71Sopenharmony_ci        .backgroundColor(0xf56c6c)
33e41f4b71Sopenharmony_ci        .width(100)
34e41f4b71Sopenharmony_ci        .height(100)
35e41f4b71Sopenharmony_ci        // Step 2: Set the declared state variable to the related animatable property API.
36e41f4b71Sopenharmony_ci        .scale({ x: this.SetAnimation.isAnimation ? 2 : 1, y: this.SetAnimation.isAnimation ? 2 : 1 })
37e41f4b71Sopenharmony_ci        // Step 4: Enable the implicit animation. When the end value of the animation changes, the system automatically adds the smoothing animation.
38e41f4b71Sopenharmony_ci        .animation({ curve: curves.springMotion(0.4, 0.8) })
39e41f4b71Sopenharmony_ci
40e41f4b71Sopenharmony_ci      Button('Click')
41e41f4b71Sopenharmony_ci        .margin({ top: 200 })
42e41f4b71Sopenharmony_ci        // Step 3: Change the state variable value through the click event, which then changes the property value.
43e41f4b71Sopenharmony_ci        .onClick(() => {
44e41f4b71Sopenharmony_ci          this.SetAnimation.set()
45e41f4b71Sopenharmony_ci        })
46e41f4b71Sopenharmony_ci    }
47e41f4b71Sopenharmony_ci    .width('100%')
48e41f4b71Sopenharmony_ci    .height('100%')
49e41f4b71Sopenharmony_ci    .justifyContent(FlexAlign.Center)
50e41f4b71Sopenharmony_ci  }
51e41f4b71Sopenharmony_ci}
52e41f4b71Sopenharmony_ci```
53e41f4b71Sopenharmony_ci
54e41f4b71Sopenharmony_ci![en-us_image_0000001599971890](figures/en-us_image_0000001599971890.gif)
55e41f4b71Sopenharmony_ci
56e41f4b71Sopenharmony_ci
57e41f4b71Sopenharmony_ci
58e41f4b71Sopenharmony_ci## Smoothing Between Gestures and Animations
59e41f4b71Sopenharmony_ci
60e41f4b71Sopenharmony_ciIn scenarios where gestures are used, a property change is generally triggered when the user places or moves their finger (or fingers) on the screen, and continues after the user lifts their finger (or fingers) off the screen until the end value of the property is reached.
61e41f4b71Sopenharmony_ci
62e41f4b71Sopenharmony_ciThe initial velocity of the property change after the user lifts their finger (or fingers) should be consistent with the velocity of the property change at the moment before the user lifts their finger (or fingers). If the former is **0**, it feels like a running car stops suddenly, an unusual abrupt change not comfortable to users.
63e41f4b71Sopenharmony_ci
64e41f4b71Sopenharmony_ciIn cases where smoothing between [tap gestures](../reference/apis-arkui/arkui-ts/ts-basic-gestures-tapgesture.md) and [animations](./arkts-animation.md) is critical, for example, when scrolling a list, you can apply a responsive spring curve to the property animation running when the user places or moves their finger (or fingers) on the screen; and apply a spring curve to the property animation running after the user lifts their finger (or fingers) off the screen. For the animation following the [springMotion](../reference/apis-arkui/js-apis-curve.md#curvesspringmotion9) curve, its portion that is running after the user lifts their finger (or fingers) off the screen automatically inherits the previous velocity and starts from where the previous portion leaves off.
65e41f4b71Sopenharmony_ci
66e41f4b71Sopenharmony_ciThe following example implements a ball moving smoothly with the gesture.
67e41f4b71Sopenharmony_ci
68e41f4b71Sopenharmony_ci```ts
69e41f4b71Sopenharmony_ciimport { curves } from '@kit.ArkUI';
70e41f4b71Sopenharmony_ci
71e41f4b71Sopenharmony_ci@Entry
72e41f4b71Sopenharmony_ci@Component
73e41f4b71Sopenharmony_cistruct SpringMotionDemo {
74e41f4b71Sopenharmony_ci
75e41f4b71Sopenharmony_ci  // Step 1: Declare the related state variable.
76e41f4b71Sopenharmony_ci  @State positionX: number = 100;
77e41f4b71Sopenharmony_ci  @State positionY: number = 100;
78e41f4b71Sopenharmony_ci  diameter: number = 50;
79e41f4b71Sopenharmony_ci
80e41f4b71Sopenharmony_ci  build() {
81e41f4b71Sopenharmony_ci    Column() {
82e41f4b71Sopenharmony_ci      Row() {
83e41f4b71Sopenharmony_ci        Circle({ width: this.diameter, height: this.diameter })
84e41f4b71Sopenharmony_ci          .fill(Color.Blue)
85e41f4b71Sopenharmony_ci          // Step 2: Set the declared state variable to the related animatable property API.
86e41f4b71Sopenharmony_ci          .position({ x: this.positionX, y: this.positionY })
87e41f4b71Sopenharmony_ci          // Step 3: Change the state variable value for the time when the user places or moves their finger (or fingers) on the screen and use responsiveSpringMotion for movement toward the new value.
88e41f4b71Sopenharmony_ci          .onTouch((event?: TouchEvent) => {
89e41f4b71Sopenharmony_ci            if(event){
90e41f4b71Sopenharmony_ci              if (event.type === TouchType.Move) {
91e41f4b71Sopenharmony_ci                // When the user places or moves their finger on the screen, use the responsiveSpringMotion curve.
92e41f4b71Sopenharmony_ci                animateTo({ curve: curves.responsiveSpringMotion() }, () => {
93e41f4b71Sopenharmony_ci                  // Subtract the radius so that the center of the ball moves to where the finger is placed.
94e41f4b71Sopenharmony_ci                  this.positionX = event.touches[0].windowX - this.diameter / 2;
95e41f4b71Sopenharmony_ci                  this.positionY = event.touches[0].windowY - this.diameter / 2;
96e41f4b71Sopenharmony_ci                  console.info(`move, animateTo x:${this.positionX}, y:${this.positionY}`);
97e41f4b71Sopenharmony_ci                })
98e41f4b71Sopenharmony_ci              } else if (event.type === TouchType.Up) {
99e41f4b71Sopenharmony_ci                // Step 4: Set the end value of the state variable for after the user lifts their finger (or fingers), and use springMotion for movement toward the new value. The springMotion animation inherits the previous velocity.
100e41f4b71Sopenharmony_ci                animateTo({ curve: curves.springMotion() }, () => {
101e41f4b71Sopenharmony_ci                  this.positionX = 100;
102e41f4b71Sopenharmony_ci                  this.positionY = 100;
103e41f4b71Sopenharmony_ci                  console.info(`touchUp, animateTo x:100, y:100`);
104e41f4b71Sopenharmony_ci                })
105e41f4b71Sopenharmony_ci              }
106e41f4b71Sopenharmony_ci            }
107e41f4b71Sopenharmony_ci          })
108e41f4b71Sopenharmony_ci      }
109e41f4b71Sopenharmony_ci      .width("100%").height("80%")
110e41f4b71Sopenharmony_ci      .clip(true) // If the ball moves beyond the parent component, it is invisible.
111e41f4b71Sopenharmony_ci      .backgroundColor(Color.Orange)
112e41f4b71Sopenharmony_ci
113e41f4b71Sopenharmony_ci      Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Start, justifyContent: FlexAlign.Center }) {
114e41f4b71Sopenharmony_ci        Text("Drag the ball").fontSize(16)
115e41f4b71Sopenharmony_ci      }
116e41f4b71Sopenharmony_ci      .width("100%")
117e41f4b71Sopenharmony_ci
118e41f4b71Sopenharmony_ci      Row() {
119e41f4b71Sopenharmony_ci        Text('Click position: [x: ' + Math.round(this.positionX) + ', y:' + Math.round(this.positionY) + ']').fontSize(16)
120e41f4b71Sopenharmony_ci      }
121e41f4b71Sopenharmony_ci      .padding(10)
122e41f4b71Sopenharmony_ci      .width("100%")
123e41f4b71Sopenharmony_ci    }.height('100%').width('100%')
124e41f4b71Sopenharmony_ci  }
125e41f4b71Sopenharmony_ci}
126e41f4b71Sopenharmony_ci```
127e41f4b71Sopenharmony_ci
128e41f4b71Sopenharmony_ci![en-us_image_0000001647027001](figures/en-us_image_0000001647027001.gif)
129