• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Layout Update Animation
2
3
4[Explicit animation](../reference/arkui-ts/ts-explicit-animation.md) (**animateTo**) and [attribute animation](../reference/arkui-ts/ts-animatorproperty.md) (**animation**) are the most basic and common animation features provided by ArkUI. When the layout attributes (such as the [size](../reference/arkui-ts/ts-universal-attributes-size.md) and [position](../reference/arkui-ts/ts-universal-attributes-location.md)) attributes change, you can use the attribute animation or explicit animation to transit to the new layout parameter status based on the animation parameters.
5
6
7| Animation Type| Description                                      |
8| ---- | ---------------------------------------- |
9| Explicit animation| Triggered by changes in a closure, including component addition and deletion caused by data changes and component attribute changes.| Complex animation scenarios|
10| Attribute animation| Triggered when the attribute changes. The animation setting is simple.                     |
11
12
13## Using Explicit Animation to Create Layout Update Animation
14
15The API for explicit animation is as follows:
16
17
18```ts
19animateTo(value: AnimateParam, event: () => void): void
20```
21
22The first parameter specifies the animation parameter, and the second parameter is the closure function of the animation.
23
24The following is an example of using explicit animation to create a layout update animation. In the example, when the **\<Column>** component's **alignItems** attribute is updated, the layout of its child components changes. As long as the attribute is updated in the closure function of **animateTo**, animation is performed as configured through **animateTo** for all changes caused by the attribute toward the end value.
25
26
27```ts
28@Entry
29@Component
30struct LayoutChange {
31  // Used to control the alignItems attribute of a column.
32  @State itemAlign: HorizontalAlign = HorizontalAlign.Start;
33  allAlign: HorizontalAlign[] = [HorizontalAlign.Start, HorizontalAlign.Center, HorizontalAlign.End];
34  alignIndex: number = 0;
35
36  build() {
37    Column() {
38      Column({ space: 10 }) {
39        Button("1").width(100).height(50)
40        Button("2").width(100).height(50)
41        Button("3").width(100).height(50)
42      }
43      .margin(20)
44      .alignItems(this.itemAlign)
45      .borderWidth(2)
46      .width("90%")
47      .height(200)
48
49      Button("click").onClick(() => {
50        // The animation duration is 1000 ms, and the curve is EaseInOut.
51        animateTo({ duration: 1000, curve: Curve.EaseInOut }, () => {
52          this.alignIndex = (this.alignIndex + 1) % this.allAlign.length;
53          // Modify the this.itemAlign parameter in the closure function to change the layout of child elements in the <Column> container. The animation for transition to the new position is applied.
54          this.itemAlign = this.allAlign[this.alignIndex];
55        });
56      })
57    }
58    .width("100%")
59    .height("100%")
60  }
61}
62```
63
64
65![layoutChange1](figures/layoutChange1.gif)
66
67
68In addition to directly changing the layout, you can also change the width, height, and position of a component.
69
70
71
72```ts
73@Entry
74@Component
75struct LayoutChange2 {
76  @State myWidth: number = 100;
77  @State myHeight: number = 50;
78  // Flag. true and false correspond to a group of myWidth and myHeight values, respectively.
79  @State flag: boolean = false;
80
81  build() {
82    Column({ space: 10 }) {
83      Button("text")
84        .type(ButtonType.Normal)
85        .width(this.myWidth)
86        .height(this.myHeight)
87        .margin(20)
88      Button("area: click me")
89        .fontSize(12)
90        .margin(20)
91        .onClick(() => {
92          animateTo({ duration: 1000, curve: Curve.Ease }, () => {
93            // In the animation closure, the state variables that control the width and height of the first button are changed based on the flag settings so that the width and height of the first button are animated.
94            if (this.flag) {
95              this.myWidth = 100;
96              this.myHeight = 50;
97            } else {
98              this.myWidth = 200;
99              this.myHeight = 100;
100            }
101            this.flag = !this.flag;
102          });
103        })
104    }
105    .width("100%")
106    .height("100%")
107  }
108}
109```
110
111
112In the click event of the second button, the **animateTo** API is used to modify the **this.myWidth** and **this.myHeight** state variables in the closure. As these two state variables set the width and height of the first button, the width and height animation is performed for the first button. The display effect is shown below.
113
114
115![layoutChange2_animateTo](figures/layoutChange2_animateTo.gif)
116
117
118At the same time, the second button also produces a position animation. After the width and height of the first button are changed, the layout of other components in the column is also changed, and the second button is among those other components.
119
120
121If you do not want the second button to have an animation effect, you can use either of the following methods: 1. Add a container outside the first button so that the sizes before and after the animation are within the range of the container. In this way, the position of the second button is not affected by the position of the first button. The key code is as follows:
122
123
124
125```ts
126Column({ space: 10 }) {
127  Column() {
128    // The button is placed in a container that is large enough so that it does not affect the position of the outer component.
129    Button("text")
130      .type(ButtonType.Normal)
131      .width(this.myWidth)
132      .height(this.myHeight)
133  }
134  .margin(20)
135  .width(200)
136  .height(100)
137
138  Button("area: click me")
139    .fontSize(12)
140    .onClick(() => {
141      animateTo({ duration: 1000, curve: Curve.Ease }, () => {
142        // In the animation closure, the state variables that control the width and height of the first button are changed based on the flag settings so that the width and height of the first button are animated.
143        if (this.flag) {
144          this.myWidth = 100;
145          this.myHeight = 50;
146        } else {
147          this.myWidth = 200;
148          this.myHeight = 100;
149        }
150        this.flag = !this.flag;
151      });
152    })
153}
154.width("100%")
155.height("100%")
156```
157
158
159![layoutChange2_animateTo_change](figures/layoutChange2_animateTo_change.gif)
160
161
1622. Add layout constraints to the second button. For example, add position constraints so that the position of the second button is not affected by the width and height of the first button.  The sample code is as follows:
163
164
165
166```ts
167Column({ space: 10 }) {
168  Button("text")
169    .type(ButtonType.Normal)
170    .width(this.myWidth)
171    .height(this.myHeight)
172    .margin(20)
173
174  Button("area: click me")
175    .fontSize(12)
176    // Set the position attribute to a fixed value so that the position of the second button is not affected by the width and height of the first button.
177    .position({ x: "30%", y: 200 })
178    .onClick(() => {
179      animateTo({ duration: 1000, curve: Curve.Ease }, () => {
180        // In the animation closure, the state variables that control the width and height of the first button are changed based on the flag settings so that the width and height of the first button are animated.
181        if (this.flag) {
182          this.myWidth = 100;
183          this.myHeight = 50;
184        } else {
185          this.myWidth = 200;
186          this.myHeight = 100;
187        }
188        this.flag = !this.flag;
189      });
190    })
191}
192.width("100%")
193.height("100%")
194```
195
196
197## Using Attribute Animation to Generate Layout Update Animation
198
199Unlike explicit animation, which requires the attribute changes for triggering animation to be placed in the closure function, attribute animation does not need to use the closure. You only need to append the **animation** attribute to the target component attribute.
200
201The API of the attribute animation is as follows:
202
203
204```ts
205animation(value: AnimateParam)
206```
207
208This API accepts an animation parameter as its argument. If you want the component to generate an animation with the value change of an attribute, add this attribute before the **animation** attribute. Otherwise, you can place the attribute after the **animation** attribute. The previous example of explicit animation can be easily implemented with attribute animation. The sample code is as follows:
209
210
211
212```ts
213@Entry
214@Component
215struct LayoutChange2 {
216  @State myWidth: number = 100;
217  @State myHeight: number = 50;
218  @State flag: boolean = false;
219  @State myColor: Color = Color.Blue;
220
221  build() {
222    Column({ space: 10 }) {
223      Button("text")
224        .type(ButtonType.Normal)
225        .width(this.myWidth)
226        .height(this.myHeight)
227        // The animation takes effect only for the type, width, and height attributes. The duration is 1000 ms, and the curve is Ease.
228        .animation({ duration: 1000, curve: Curve.Ease })
229        // The animation does not take effect for the backgroundColor and margin attributes.
230        .backgroundColor(this.myColor)
231        .margin(20)
232
233      Button("area: click me")
234        .fontSize(12)
235        .onClick(() => {
236          // Change the attribute value. Animation transition is performed for attributes configured with attribute animation.
237          if (this.flag) {
238            this.myWidth = 100;
239            this.myHeight = 50;
240            this.myColor = Color.Blue;
241          } else {
242            this.myWidth = 200;
243            this.myHeight = 100;
244            this.myColor = Color.Pink;
245          }
246          this.flag = !this.flag;
247        })
248    }
249  }
250}
251```
252
253
254In the preceding example, the **animation** attribute of the first button takes effect only for the **type**, **width**, and **height** attributes written before the **animation** attribute, but does not take effect for the **backgroundColor** and **margin** attributes written after. In the running result, the **width** and **height** attributes execute the animation based on the **animation** settings, while the **backgroundColor** attribute changes without any animation applied. The display effect is shown below.
255
256
257
258
259
260
261![size-change-animation](figures/size-change-animation.gif)
262
263
264>**NOTE**
265>
266>    1. Attribute animations are executed according to the configured attribute animation settings. Each component can have its own attribute animation settings.
267>
268>    2. Explicit animations are executed on all GUI differences caused before and after animation closures, and they share the same animation settings. Therefore, explicit animations are applicable to scenarios where animations are executed in a unified manner. Explicit animations can also be used for animations caused by non-attribute variables, such as **if/else** statements and deletion of array elements used by **ForEach**.
269>
270>    3. If an attribute animation is configured for an attribute and the attribute value is changed in the explicit animation closure, the attribute animation takes precedence, under the configured animation settings.
271