1# Using the Animation Feature 2 3The animation feature provides component animation and inter-page animation, and opens the animation capability APIs for [interpolation calculation](../reference/apis/js-apis-curve.md) and [matrix transformation](../reference/apis/js-apis-matrix4.md), allowing you to design animation effects to a great extent. 4 5This section describes the following animation effects: 6 71. Animation on the splash screen: fade-in and fade-out of the logo. 82. Transition animation of shared elements on the food list page and food details page. 9 10## AnimateTo for Splash Screen Animation 11 12Component animations include attribute animations and **animateTo** explicit animations. 13 141. Attribute animation: animation for the universal attribute changes of a component. 152. Explicit animation: animation for a component changing from state A to state B, including the style, location information, and node addition and deletion. You only need to specify the start and end states, without the need for paying attention to the change process. The **animateTo** class also provides the callback for the playback state change events, which is an enhancement and encapsulation of the attribute animation. 16 17The splash screen animation refers to the fade-in and fade-out of the logo. After the animation is complete, the food list page is displayed. The following describes how to use **animateTo** to implement the splash screen animation. 18 191. Configure the splash screen animation to automatically play. The expected effect is as follows: **animateTo** automatically starts to play the animation once the logo page is displayed. Call the **onAppear** API of **Shape** to set the explicit animation. 20 21 ```ts 22 Shape() { 23 ... 24 } 25 .onAppear(() => { 26 animateTo() 27 }) 28 ``` 29 302. Create member variables of **opacity** and **scale** values and decorate them using the **@State** decorator, which indicates that the data is stateful and its change will trigger page refresh. 31 32 ```ts 33 @Entry 34 @Component 35 struct Logo { 36 @State private opacityValue: number = 0 37 @State private scaleValue: number = 0 38 build() { 39 Shape() { 40 ... 41 } 42 .scale({ x: this.scaleValue, y: this.scaleValue }) 43 .opacity(this.opacityValue) 44 .onAppear(() => { 45 animateTo() 46 }) 47 } 48 } 49 ``` 50 513. Sets the **animateTo** animation curve. The acceleration curve of the logo is slow first and then fast. The Bezier curve cubicBezier, **cubicBezier(0.4, 0, 1, 1)** is used. 52 53 Before using interpolation calculation in the **animateTo**, you must import the **Curves** module. 54 55 ```ts 56 import Curves from '@ohos.curves' 57 ``` 58 59 The **@ohos.curves** module provides the linear curve. For initialization function of the linear, step, cubicBezier, and spring interpolation curves, an interpolation curve object can be created based on the input parameters. 60 61 ```ts 62 @Entry 63 @Component 64 struct Logo { 65 @State private opacityValue: number = 0 66 @State private scaleValue: number = 0 67 private curve1 = Curves.cubicBezier(0.4, 0, 1, 1) 68 69 build() { 70 Shape() { 71 ... 72 } 73 .scale({ x: this.scaleValue, y: this.scaleValue }) 74 .opacity(this.opacityValue) 75 .onAppear(() => { 76 animateTo({ 77 curve: this.curve1 78 }) 79 }) 80 } 81 } 82 ``` 83 844. Set the animation duration to 1s, set the delay to 0.1s, and set the closure function for displaying animation events. That is, set **opacityValue** and **scaleValue** to change from 0 to 1 from the start point to the end point. In this way, the logo fades in and out. 85 86 ```ts 87 @Entry 88 @Component 89 struct Logo { 90 @State private opacityValue: number = 0 91 @State private scaleValue: number = 0 92 private curve1 = Curves.cubicBezier(0.4, 0, 1, 1) 93 94 build() { 95 Shape() { 96 ... 97 } 98 .scale({ x: this.scaleValue, y: this.scaleValue }) 99 .opacity(this.opacityValue) 100 .onAppear(() => { 101 animateTo({ 102 duration: 1000, 103 curve: this.curve1, 104 delay: 100, 105 }, () => { 106 this.opacityValue = 1 107 this.scaleValue = 1 108 }) 109 }) 110 } 111 } 112 ``` 113 1145. After the splash screen animation plays for 1 second, the **FoodCategoryList** page is displayed. Set the **onFinish** callback of **animateTo**. Invoke the **setTimeout** API of the timer. After a delay of 1s, call **router.replace** to display the **FoodCategoryList** page. 115 116 ```ts 117 import router from '@ohos.router' 118 119 @Entry 120 @Component 121 struct Logo { 122 @State private opacityValue: number = 0 123 @State private scaleValue: number = 0 124 private curve1 = Curves.cubicBezier(0.4, 0, 1, 1) 125 126 build() { 127 Shape() { 128 ... 129 } 130 .scale({ x: this.scaleValue, y: this.scaleValue }) 131 .opacity(this.opacityValue) 132 .onAppear(() => { 133 134 animateTo({ 135 duration: 1000, 136 curve: this.curve1, 137 delay: 100, 138 onFinish: () => { 139 setTimeout(() => { 140 router.replaceUrl({ url: "pages/FoodCategoryList" }) 141 }, 1000); 142 } 143 }, () => { 144 this.opacityValue = 1 145 this.scaleValue = 1 146 }) 147 }) 148 } 149 } 150 ``` 151 152 The code is as follows: 153 154 ```ts 155 import Curves from '@ohos.curves' 156 import router from '@ohos.router' 157 158 @Entry 159 @Component 160 struct Logo { 161 @State private opacityValue: number = 0 162 @State private scaleValue: number = 0 163 private curve1 = Curves.cubicBezier(0.4, 0, 1, 1) 164 private pathCommands1: string = 'M319.5 128.1 c103.5 0 187.5 84 187.5 187.5 v15 a172.5 172.5 0 0 3 -172.5 172.5 H198 a36 36 0 0 3 -13.8 -1 207 207 0 0 0 87 -372 h48.3 z' 165 private pathCommands2: string = 'M270.6 128.1 h48.6 c51.6 0 98.4 21 132.3 54.6 a411 411 0 0 3 -45.6 123 c-25.2 45.6 -56.4 84 -87.6 110.4 a206.1 206.1 0 0 0 -47.7 -288 z' 166 167 build() { 168 Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { 169 Shape() { 170 Path() 171 .commands('M162 128.7 a222 222 0 0 1 100.8 374.4 H198 a36 36 0 0 3 -36 -36') 172 .fill(Color.White) 173 .stroke(Color.Transparent) 174 Path() 175 .commands(this.pathCommands1) 176 .fill('none') 177 .stroke(Color.Transparent) 178 .linearGradient( 179 { 180 angle: 30, 181 colors: [["#C4FFA0", 0], ["#ffffff", 1]] 182 }) 183 .clip(new Path().commands(this.pathCommands1)) 184 185 Path() 186 .commands(this.pathCommands2) 187 .fill('none') 188 .stroke(Color.Transparent) 189 .linearGradient( 190 { 191 angle: 50, 192 colors: [['#8CC36A', 0.1], ["#B3EB90", 0.4], ["#ffffff", 0.7]] 193 }) 194 .clip(new Path().commands(this.pathCommands2)) 195 } 196 .height('630px') 197 .width('630px') 198 .scale({ x: this.scaleValue, y: this.scaleValue }) 199 .opacity(this.opacityValue) 200 .onAppear(() => { 201 animateTo({ 202 duration: 1000, 203 curve: this.curve1, 204 delay: 100, 205 onFinish: () => { 206 setTimeout(() => { 207 router.replaceUrl({ url: "pages/FoodCategoryList" }) 208 }, 1000); 209 } 210 }, () => { 211 this.opacityValue = 1 212 this.scaleValue = 1 213 }) 214 }) 215 216 Text('Healthy Diet') 217 .fontSize(26) 218 .fontColor(Color.White) 219 .margin({ top: 300 }) 220 221 Text('Healthy life comes from a balanced diet') 222 .fontSize(17) 223 .fontColor(Color.White) 224 .margin({ top: 4 }) 225 } 226 .width('100%') 227 .height('100%') 228 .linearGradient( 229 { 230 angle: 180, 231 colors: [['#BDE895', 0.1], ["#95DE7F", 0.6], ["#7AB967", 1]] 232 }) 233 } 234 } 235 ``` 236 237  238 239## Page Transition Animation 240 241Implement the shared element transition between the food list page and the food details page. That is, after you click **FoodListItem** or **FoodGridItem**, the food thumbnail is zoomed in, and then you are redirected to the large image on the food details page. 242 2431. Set the **sharedTransition** method for the **\<Image>** component of **FoodListItem** and **FoodGridItem**. The transition ID is **foodItem.id**, the duration of the transition animation is 1s, and the delay is 0.1s. The change curve is **Curves.cubicBezier(0.2, 0.2, 0.1, 1.0)**. You need to import the **Curves** module first. 244 245 During the shared element transition, the attributes of the current element are carried. Therefore, create a **\<Row>** component as the parent component of the **\<Image>** component, and set the background color on the **\<Row>** component. 246 247 Set **autoResize** to **false** for the **\<Image>** component of **FoodListItem**. The **\<Image>** component adjusts the size of the image source based on the final display area by default to optimize the image rendering performance. In the transition animation, the image will be reloaded during the zoom-in process. Therefore, to ensure the smoothness of the transition animation, set **autoResize** to **false**. 248 249 ```ts 250 // FoodList.ets 251 import Curves from '@ohos.curves' 252 253 @Component 254 struct FoodListItem { 255 private foodItem: FoodData 256 build() { 257 Navigator({ target: 'pages/FoodDetail' }) { 258 Flex({ justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) { 259 Row() { 260 Image(this.foodItem.image) 261 .objectFit(ImageFit.Contain) 262 .autoResize(false) 263 .height(40) 264 .width(40) 265 .sharedTransition(this.foodItem.id, { duration: 1000, curve: Curves.cubicBezier(0.2, 0.2, 0.1, 1.0), delay: 100 }) 266 } 267 268 .margin({ right: 16 }) 269 Text(this.foodItem.name) 270 .fontSize(14) 271 .flexGrow(1) 272 Text(this.foodItem.calories + ' kcal') 273 .fontSize(14) 274 } 275 .height(64) 276 } 277 .params({ foodData: this.foodItem }) 278 .margin({ right: 24, left:32 }) 279 } 280 } 281 282 @Component 283 struct FoodGridItem { 284 private foodItem: FoodData 285 build() { 286 Column() { 287 Row() { 288 Image(this.foodItem.image) 289 .objectFit(ImageFit.Contain) 290 .autoResize(false) 291 .height(152) 292 .width('100%') 293 .sharedTransition(this.foodItem.id, { duration: 1000, curve: Curves.cubicBezier(0.2, 0.2, 0.1, 1.0), delay: 100 }) 294 } 295 Flex({ justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) { 296 Text(this.foodItem.name) 297 .fontSize(14) 298 .flexGrow(1) 299 .padding({ left: 8 }) 300 Text(this.foodItem.calories + 'kcal') 301 .fontSize(14) 302 .margin({ right: 6 }) 303 } 304 .height(32) 305 .width('100%') 306 .backgroundColor('#FFe5e5e5') 307 } 308 .height(184) 309 .width('100%') 310 .onClick(() => { 311 router.pushUrl({ url: 'pages/FoodDetail', params: { foodData: this.foodItem } }) 312 }) 313 } 314 } 315 316 317 ``` 318 3192. Sets the **sharedTransition** method for the **\<Image>** component of **FoodImageDisplay** on the **FoodDetail** page. The setting method is the same as that mentioned above. 320 321 ```ts 322 import Curves from '@ohos.curves' 323 324 @Component 325 struct FoodImageDisplay { 326 private foodItem: FoodData 327 build() { 328 Stack({ alignContent: Alignment.BottomStart }) { 329 Image(this.foodItem.image) 330 .objectFit(ImageFit.Contain) 331 .sharedTransition(this.foodItem.id, { duration: 1000, curve: Curves.cubicBezier(0.2, 0.2, 0.1, 1.0), delay: 100 }) 332 Text(this.foodItem.name) 333 .fontSize(26) 334 .fontWeight(500) 335 .margin({ left: 26, bottom: 17.4 }) 336 } 337 .height(357) 338 } 339 } 340 ``` 341 342  343 344 Now we have completed the drawing of the startup logo, splash screen animation, and transition animation between pages. By applying and combining the various animation APIs in the declarative development framework, you can create a more immersive experience for your applications. 345