1# Animation Smoothing
2
3
4When 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.
5
6Assume 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.
7
8The 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.
9
10```ts
11import { curves } from '@kit.ArkUI';
12class SetSlt{
13  isAnimation:boolean = true
14  set():void{
15    this.isAnimation = !this.isAnimation;
16  }
17}
18@Entry
19@Component
20struct AnimationToAnimationDemo {
21// Step 1: Declare the related state variable.
22  @State SetAnimation: SetSlt = new SetSlt();
23
24  build() {
25    Column() {
26      Text('ArkUI')
27        .fontWeight(FontWeight.Bold)
28        .fontSize(12)
29        .fontColor(Color.White)
30        .textAlign(TextAlign.Center)
31        .borderRadius(10)
32        .backgroundColor(0xf56c6c)
33        .width(100)
34        .height(100)
35        // Step 2: Set the declared state variable to the related animatable property API.
36        .scale({ x: this.SetAnimation.isAnimation ? 2 : 1, y: this.SetAnimation.isAnimation ? 2 : 1 })
37        // Step 4: Enable the implicit animation. When the end value of the animation changes, the system automatically adds the smoothing animation.
38        .animation({ curve: curves.springMotion(0.4, 0.8) })
39
40      Button('Click')
41        .margin({ top: 200 })
42        // Step 3: Change the state variable value through the click event, which then changes the property value.
43        .onClick(() => {
44          this.SetAnimation.set()
45        })
46    }
47    .width('100%')
48    .height('100%')
49    .justifyContent(FlexAlign.Center)
50  }
51}
52```
53
54![en-us_image_0000001599971890](figures/en-us_image_0000001599971890.gif)
55
56
57
58## Smoothing Between Gestures and Animations
59
60In 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.
61
62The 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.
63
64In 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.
65
66The following example implements a ball moving smoothly with the gesture.
67
68```ts
69import { curves } from '@kit.ArkUI';
70
71@Entry
72@Component
73struct SpringMotionDemo {
74
75  // Step 1: Declare the related state variable.
76  @State positionX: number = 100;
77  @State positionY: number = 100;
78  diameter: number = 50;
79
80  build() {
81    Column() {
82      Row() {
83        Circle({ width: this.diameter, height: this.diameter })
84          .fill(Color.Blue)
85          // Step 2: Set the declared state variable to the related animatable property API.
86          .position({ x: this.positionX, y: this.positionY })
87          // 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.
88          .onTouch((event?: TouchEvent) => {
89            if(event){
90              if (event.type === TouchType.Move) {
91                // When the user places or moves their finger on the screen, use the responsiveSpringMotion curve.
92                this.getUIContext()?.animateTo({ curve: curves.responsiveSpringMotion() }, () => {
93                  // Subtract the radius so that the center of the ball moves to where the finger is placed.
94                  this.positionX = event.touches[0].windowX - this.diameter / 2;
95                  this.positionY = event.touches[0].windowY - this.diameter / 2;
96                  console.info(`move, animateTo x:${this.positionX}, y:${this.positionY}`);
97                })
98              } else if (event.type === TouchType.Up) {
99                // 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.
100                this.getUIContext()?.animateTo({ curve: curves.springMotion() }, () => {
101                  this.positionX = 100;
102                  this.positionY = 100;
103                  console.info(`touchUp, animateTo x:100, y:100`);
104                })
105              }
106            }
107          })
108      }
109      .width("100%").height("80%")
110      .clip(true) // If the ball moves beyond the parent component, it is invisible.
111      .backgroundColor(Color.Orange)
112
113      Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Start, justifyContent: FlexAlign.Center }) {
114        Text("Drag the ball").fontSize(16)
115      }
116      .width("100%")
117
118      Row() {
119        Text('Click position: [x: ' + Math.round(this.positionX) + ', y:' + Math.round(this.positionY) + ']').fontSize(16)
120      }
121      .padding(10)
122      .width("100%")
123    }.height('100%').width('100%')
124  }
125}
126```
127
128![en-us_image_0000001647027001](figures/en-us_image_0000001647027001.gif)
129