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 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 129