1# Frame Animation (ohos.animator) 2 3The frame animation allows you to adjust your animation properties on each frame, thanks to its per-frame callback. By leveraging the **onFrame** callback, you can dynamically set property values on each frame, creating smooth and natural animations. For details about the frame animation APIs, see [@ohos.animator (Animator)](../reference/apis-arkui/js-apis-animator.md). 4 5Compared with the property animation, the frame animation offers the benefits of real-time visibility into the animation process and allows you to modify UI values on the fly. In addition, it provides high responsiveness to events and can be paused as needed. However, it is worth noting that the frame animation may not be as performant as the property animation. Therefore, where the property animation meets the requirements, you are advised to use the property animation APIs. For details, see [Implementing Property Animation](./arkts-attribute-animation-apis.md). The table below provides a comparison between the property animation and frame animation. 6 7| Name| Implementation| Event Response| Pausable| Performance| 8| -------- | -------- | -------- | -------- |-------- | 9| Frame animation (ohos.animator)| Allows real-time modification and updating of UI properties on each frame.| Responds in real time| Yes| Relatively lower| 10| Property animation| Calculates the final state of the animation, with the UI reflecting only the end state, not the intermediate rendering values.| Responds to the end state| No| Generally higher| 11 12The following figures illustrate the difference: The frame animation offers real-time responsiveness, whereas the property animation reacts to the final state of the animation. 13 14 15 16 17 18## Using Frame Animation to Implement Animation Effects 19 20To create a simple animator and print the current interpolation value in each frame callback: 21 221. Import dependencies. 23 24 ```ts 25 import { AnimatorOptions, AnimatorResult } from '@kit.ArkUI'; 26 ``` 27 282. Create an animator object. 29 30 ```ts 31 // Initial options for creating an animator object 32 let options: AnimatorOptions = { 33 duration: 1500, 34 easing: "friction", 35 delay: 0, 36 fill: "forwards", 37 direction: "normal", 38 iterations: 2, 39 // Initial frame value used for interpolation in the onFrame callback 40 begin: 200.0, 41 // End frame value used for interpolation in the onFrame callback 42 end: 400.0 43 }; 44 let result: AnimatorResult = this.getUIContext().createAnimator(options); 45 // Set up a callback for when a frame is received, so that the onFrame callback is called for every frame throughout the animation playback process. 46 result.onFrame = (value: number) => { 47 console.log("current value is :" + value); 48 } 49 ``` 50 513. Play the animation. 52 53 ```ts 54 // Play the animation. 55 result.play(); 56 ``` 57 584. After the animation has finished executing, manually release the **AnimatorResult** object. 59 60 ```ts 61 // Release the animation object. 62 result = undefined; 63 ``` 64 65## Using Frame Animation to Implement a Ball's Parabolic Motion 66 671. Import dependencies. 68 69 ```ts 70 import { AnimatorOptions, AnimatorResult } from '@kit.ArkUI'; 71 ``` 72 732. Define the component to be animated. 74 75 ```ts 76 Button() 77 .width(60) 78 .height(60) 79 .translate({ x: this.translateX, y: this.translateY }) 80 ``` 81 823. Create an **AnimatorResult** Object in **onPageShow**. 83 84 ```ts 85 onPageShow(): void { 86 // Create an animatorResult object. 87 this.animatorOptions = this.getUIContext().createAnimator(options); 88 this.animatorOptions.onFrame = (progress: number) => { 89 this.translateX = progress; 90 if (progress > this.topWidth && this.translateY < this.bottomHeight) { 91 this.translateY = Math.pow(progress - this.topWidth, 2) * this.g; 92 } 93 } 94 // Invoked when the animation is canceled. 95 this.animatorOptions.onCancel = () => { 96 this.animatorStatus = 'Canceled' 97 } 98 // Invoked when the animation finishes playing. 99 this.animatorOptions.onFinish = () => { 100 this.animatorStatus = 'Finished' 101 } 102 // Invoked when the animation repeats. 103 this.animatorOptions.onRepeat = () => { 104 console.log("Animation repeating"); 105 } 106 } 107 ``` 108 1094. Define buttons for controlling the animation. 110 111 ```ts 112 Button('Play').onClick(() => { 113 this.animatorOptions?.play(); 114 this.animatorStatus = 'Playing' 115 }).width(80).height(35) 116 Button("Reset").onClick(() => { 117 this.translateX = 0; 118 this.translateY = 0; 119 }).width(80).height(35) 120 Button("Pause").onClick(() => { 121 this.animatorOptions?.pause(); 122 this.animatorStatus = 'Paused' 123 }).width(80).height(35) 124 ``` 1255. Destroy the animation in the page's **onPageHide** lifecycle callback to avoid memory leak. 126 ```ts 127 onPageHide(): void { 128 this.animatorOptions = undefined; 129 } 130 ``` 131 132A complete example is as follows: 133 134```ts 135import { AnimatorOptions, AnimatorResult } from '@kit.ArkUI'; 136 137@Entry 138@Component 139struct Index { 140 @State animatorOptions: AnimatorResult | undefined = undefined; 141 @State animatorStatus: string =' Created' 142 begin: number = 0; 143 end: number = 300 144 topWidth: number = 150; 145 bottomHeight: number = 100; 146 g: number = 0.18 147 animatorOption: AnimatorOptions = { 148 duration: 4000, 149 delay: 0, 150 easing: 'linear', 151 iterations: 1, 152 fill: "forwards", 153 direction: 'normal', 154 begin: this.begin, 155 end: this.end 156 }; 157 @State translateX: number = 0; 158 @State translateY: number = 0; 159 160 onPageShow(): void { 161 this.animatorOptions = this.getUIContext().createAnimator(this.animatorOption) 162 this.animatorOptions.onFrame = (progress: number) => { 163 this.translateX = progress; 164 if (progress > this.topWidth && this.translateY < this.bottomHeight) { 165 this.translateY = Math.pow(progress - this.topWidth, 2) * this.g; 166 } 167 } 168 this.animatorOptions.onCancel = () => { 169 this.animatorStatus = 'Canceled' 170 } 171 this.animatorOptions.onFinish = () => { 172 this.animatorStatus = 'Finished' 173 } 174 this.animatorOptions.onRepeat = () => { 175 console.log("Animation repeating"); 176 } 177 } 178 179 onPageHide(): void { 180 this.animatorOptions = undefined; 181 } 182 183 build() { 184 Column() { 185 Column({ space: 30 }) { 186 Button('Play').onClick(() => { 187 this.animatorOptions?.play(); 188 this.animatorStatus = 'Playing'; 189 }).width(80).height(35) 190 Button("Reset").onClick(() => { 191 this.translateX = 0; 192 this.translateY = 0; 193 }).width(80).height(35) 194 Button("Pause").onClick(() => { 195 this.animatorOptions?.pause(); 196 this.animatorStatus = 'Paused'; 197 }).width(80).height(35) 198 }.width("100%").height('25%') 199 200 Stack() { 201 Button() 202 .width(60) 203 .height(60) 204 .translate({ x: this.translateX, y: this.translateY }) 205 } 206 .width("100%") 207 .height('45%') 208 .align(Alignment.Start) 209 210 Text("Current animation state: "+ this.animatorStatus) 211 }.width("100%").height('100%') 212 } 213} 214``` 215 216 217