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![Alt text](figures/ohos.animator.gif)
15
16![Alt text](figures/animation.gif)
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![en-us_image_0000001599958466](figures/animatorSimple.gif)
217