• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Tabs
2
3The **Tabs** component is a container component that allows users to switch between content views through tabs. Each tab page corresponds to a content view.
4
5>  **NOTE**
6>
7>  This component is supported since API version 7. Updates will be marked with a superscript to indicate their earliest API version.
8>
9>  Since API version 11, this component supports the safe area attribute by default, with the default attribute value being **expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.BOTTOM])**. You can override this attribute to change the default behavior. In earlier versions, you need to use the [expandSafeArea](ts-universal-attributes-expand-safe-area.md) attribute to implement the safe area feature.
10
11
12## Child Components
13
14Custom components cannot be used as child components. Only the [TabContent](ts-container-tabcontent.md) child component is allowed, with support for [if/else](../../../quick-start/arkts-rendering-control-ifelse.md) and [ForEach](../../../quick-start/arkts-rendering-control-foreach.md) rendering control. In addition, the **if/else** and **ForEach** statements support **TabContent** components only, but not custom components.
15
16>  **NOTE**
17>
18>  If the child component has the **visibility** attribute set to **None** or **Hidden**, it is hidden but still takes up space in the layout.
19>
20>  The **TabContent** child component is not destroyed once it is displayed. If you need to implement lazy loading and resource release of pages, see [Example 12](#example-12-implementing-lazy-loading-and-resource-release-of-pages).
21
22
23## APIs
24
25Tabs(options?: TabsOptions)
26
27Creates a **Tabs** component.
28
29**Atomic service API**: This API can be used in atomic services since API version 11.
30
31**System capability**: SystemCapability.ArkUI.ArkUI.Full
32
33**Parameters**
34
35| Name| Type        | Mandatory| Description|
36| -------- | -------- | -------- | -------- |
37| options | [TabsOptions](#tabsoptions15) | No| Options of the **Tabs** component.|
38
39## TabsOptions<sup>15+</sup>
40
41Provides parameters for configuring the **Tabs** component, including tab positions, the current index of the displayed tab, the **Tabs** controller, and [universal attributes](ts-component-general-attributes.md) for the **TabBar**.
42
43**Atomic service API**: This API can be used in atomic services since API version 15.
44
45**System capability**: SystemCapability.ArkUI.ArkUI.Full
46
47| Name        | Type                             | Mandatory  | Description                                    |
48| ----------- | --------------------------------- | ---- | ---------------------------------------- |
49| barPosition | [BarPosition](#barposition)| No   | Position of the **Tabs** component.<br>Default value: **BarPosition.Start**  |
50| index       | number                            | No   | Index of the currently displayed tab.<br>Default value: **0**<br>**NOTE**<br>A value less than 0 evaluates to the default value.<br>The value ranges from 0 to the number of **TabContent** nodes minus 1.<br>When the tab is switched by changing the index, the tab switching animation does not take effect. When **changeIndex** of **TabController** is used for tab switching, the tab switching animation is enabled by default. You can disable the animation by setting **animationDuration** to **0**.<br>Since API version 10, this parameter supports two-way binding through [$$](../../../quick-start/arkts-two-way-sync.md).<br>When the **Tabs** component is rebuilt, system resources are switched (for example, system font or theme changes), or component attributes change, the **Tab** component will switch to the one specified by **index**. To prevent this behavior, you are advised to use two-way binding.|
51| controller  | [TabsController](#tabscontroller) | No   | Tab controller.                              |
52| barModifier<sup>15+</sup>  | [CommonModifier](#commonmodifier15) | No   | [Universal attributes](ts-component-general-attributes.md) of the tab bar.<br>**NOTE**<br>If this parameter is dynamically set to **undefined**, the current state will be preserved, and universal attributes will not be reset.<br>If the setting switches from one **CommonModifier** to another, overlapping attributes will be overwritten, while non-overlapping attributes will coexist without resetting the attributes of the previous **CommonModifier**.<br>The [barWidth](#barwidth), [barHeight](#barheight), [barBackgroundColor](#barbackgroundcolor10), and [barBackgroundBlurStyle](#barbackgroundblurstyle11) attributes of **Tabs** will overwrite the [width](ts-universal-attributes-size.md#width), [height](ts-universal-attributes-size.md#height), [backgroundColor](ts-universal-attributes-background.md#backgroundcolor), and [backgroundBlurStyle](ts-universal-attributes-background.md#backgroundblurstyle9) attributes of **CommonModifier**.<br>The [align](ts-universal-attributes-location.md#align) attribute works only in [BarMode.Scrollable](#barmode10-1) mode. In addition, for a horizontal **Tabs** component, it only takes effect when [nonScrollableLayoutStyle](#scrollablebarmodeoptions10) is set to an invalid value or is not set.<br>When set to the bottom tab style, [tabBar](ts-container-tabcontent.md#tabbar9) attribute of the [TabContent](ts-container-tabcontent.md) component does not support the dragging feature.|
53
54## BarPosition
55
56Enumerates the positions of the **Tabs** component.
57
58**Atomic service API**: This API can be used in atomic services since API version 11.
59
60**System capability**: SystemCapability.ArkUI.ArkUI.Full
61
62| Name | Description                                                        |
63| ----- | ------------------------------------------------------------ |
64| Start | If the **vertical** attribute is set to **true**, the tab is on the left of the container. If the **vertical** attribute is set to **false**, the tab is on the top of the container.|
65| End   | If the **vertical** attribute is set to **true**, the tab is on the right of the container. If the **vertical** attribute is set to **false**, the tab is at the bottom of the container.|
66
67
68## Attributes
69
70In addition to the [universal attributes](ts-component-general-attributes.md), the following attributes are supported.
71
72### vertical
73
74vertical(value: boolean)
75
76Sets whether to use vertical tabs.
77
78**Atomic service API**: This API can be used in atomic services since API version 11.
79
80**System capability**: SystemCapability.ArkUI.ArkUI.Full
81
82**Parameters**
83
84| Name| Type   | Mandatory| Description                                                        |
85| ------ | ------- | ---- | ------------------------------------------------------------ |
86| value  | boolean | Yes  | Whether to use vertical tabs.<br>The value **true** means to use vertical tabs, and **false** means to use horizontal tabs.<br>Default value: **false**<br>If set to have a height of **auto**, horizontal tabs auto-adapt the height to child components, which is calculated as follows: Tab bar height + Divider width + Tab content height + Top and bottom paddings + Top and bottom border widths.<br>If set to have a width of **auto**, vertical tabs auto-adapt the width to child components, which is calculated as follows: Tab bar width + Divider width + Tab content width + Left and right paddings + Left and right border widths.<br>To avoid animation jitter when switching between tabs, maintain a consistent size for child components on each tab.|
87
88### scrollable
89
90scrollable(value: boolean)
91
92Sets whether the tabs are scrollable.
93
94**Atomic service API**: This API can be used in atomic services since API version 11.
95
96**System capability**: SystemCapability.ArkUI.ArkUI.Full
97
98**Parameters**
99
100| Name| Type   | Mandatory| Description                                                        |
101| ------ | ------- | ---- | ------------------------------------------------------------ |
102| value  | boolean | Yes  | Whether the tabs are scrollable.<br>**true** (default): The tabs are scrollable.<br> **false**: The tabs are not scrollable.|
103
104### barMode
105
106barMode(value: BarMode, options?: ScrollableBarModeOptions)
107
108Sets the tab bar layout mode.
109
110**Atomic service API**: This API can be used in atomic services since API version 11.
111
112**System capability**: SystemCapability.ArkUI.ArkUI.Full
113
114**Parameters**
115
116| Name               | Type                                                        | Mandatory| Description                                                        |
117| --------------------- | ------------------------------------------------------------ | ---- | ------------------------------------------------------------ |
118| value                 | [BarMode](#barmode)                                  | Yes  | Layout mode.<br>Default value: **BarMode.Fixed**                                                |
119| options<sup>10+</sup> | [ScrollableBarModeOptions](#scrollablebarmodeoptions10)| No  | Layout style of the tab bar in scrollable mode.<br>**NOTE**<br>This parameter is effective only when the tab bar is in horizontal scrollable mode.|
120
121### barMode<sup>10+</sup>
122
123barMode(value: BarMode.Fixed)
124
125Sets the tab bar layout mode to **BarMode.Fixed**.
126
127**Atomic service API**: This API can be used in atomic services since API version 11.
128
129**System capability**: SystemCapability.ArkUI.ArkUI.Full
130
131**Parameters**
132
133| Name   | Type                            | Mandatory| Description                                   |
134| -------- | -------------------------------- | ---- | ------------------------------------ |
135| value    | [BarMode.Fixed](#barmode)| Yes  | The width of each tab is determined by equally dividing the number of tabs by the bar width (or bar height in the vertical layout).  |
136
137### barMode<sup>10+</sup>
138
139barMode(value: BarMode.Scrollable, options: ScrollableBarModeOptions)
140
141Sets the tab bar layout mode to **BarMode.Scrollable**.
142
143**Atomic service API**: This API can be used in atomic services since API version 11.
144
145**System capability**: SystemCapability.ArkUI.ArkUI.Full
146
147**Parameters**
148
149| Name   | Type                             | Mandatory| Description                                   |
150| -------- | --------------------------------- | ---- | ------------------------------------- |
151| value    | [BarMode.Scrollable](#barmode)| Yes  | The width of each tab is determined by the actual layout. The tabs are scrollable in the following case: In horizontal layout, the total width exceeds the tab bar width; in vertical layout, the total height exceeds the tab bar height.       |
152| options | [ScrollableBarModeOptions](#scrollablebarmodeoptions10)| Yes  | Layout style of the tab bar in scrollable mode.<br>**NOTE**<br>This parameter is effective only when the tab bar is in scrollable mode. |
153
154### barWidth
155
156barWidth(value: Length)
157
158Sets the width of the tab bar. If the set value is less than 0 or greater than the width of the **Tabs** component, the default value is used.
159
160**Atomic service API**: This API can be used in atomic services since API version 11.
161
162**System capability**: SystemCapability.ArkUI.ArkUI.Full
163
164**Parameters**
165
166| Name| Type                                     | Mandatory| Description                                                        |
167| ------ | ----------------------------------------- | ---- | ------------------------------------------------------------ |
168| value  | [Length](ts-types.md#length)<sup>8+</sup> | Yes  | Width of the tab bar.<br>Default value:<br>If the tab bar has the **vertical** attribute set to **false** and does not have [SubTabBarStyle](ts-container-tabcontent.md#subtabbarstyle9) or [BottomTabBarStyle](ts-container-tabcontent.md#bottomtabbarstyle9) specified, the default value is the width of the **Tabs** component.<br>If neither **SubTabBarStyle** nor **BottomTabBarStyle** is set, and the **vertical** attribute is **true**, the default value is 56 vp.<br>If **SubTabBarStyle** is set, and the **vertical** attribute is **false**, the default value is the width of the **Tabs** component.<br>If **SubTabBarStyle** is set, and the **vertical** attribute is **true**, the default value is 56 vp.<br>If **BottomTabBarStyle** is set, and the **vertical** attribute is **true**, the default value is 96 vp.<br>If **BottomTabBarStyle** is set, and the **vertical** attribute is **false**, the default value is the width of the **Tabs** component.|
169
170### barHeight
171
172barHeight(value: Length)
173
174Sets the height of the tab bar. If this attribute is set to **'auto'**, which takes effect only in horizontal mode, the tab bar adapts to the height of its child components. If the set value is less than 0 or greater than the height of the **Tabs** component, the default value is used.
175
176In versions earlier than API version 14, setting **barHeight** to a fixed value restricts the tab bar from extending beyond the bottom safe area. Since API version 14, the [safeAreaPadding](./ts-universal-attributes-size.md#safeareapadding14) attribute is supported. When **safeAreaPadding** is set to 0 or is not explicitly set, the tab bar is allowed to extend beyond the bottom safe area.
177
178**Atomic service API**: This API can be used in atomic services since API version 11.
179
180**System capability**: SystemCapability.ArkUI.ArkUI.Full
181
182**Parameters**
183
184| Name| Type                                     | Mandatory| Description                                                        |
185| ------ | ----------------------------------------- | ---- | ------------------------------------------------------------ |
186| value  | [Length](ts-types.md#length)<sup>8+</sup> | Yes  | Height of the tab bar.<br>Default value:<br>If the tab bar has the **vertical** attribute set to **false** and does not have a style specified, the default value is 56 vp.<br>If the tab bar has the **vertical** attribute set to **true** and does not have a style specified, the default value is the height of the **Tabs** component.<br>If [SubTabBarStyle](ts-container-tabcontent.md#subtabbarstyle9) is set, and the **vertical** attribute is **false**, the default value is 56 vp.<br>If **SubTabBarStyle** is set, and the **vertical** attribute is **true**, the default value is the height of the **Tabs** component.<br>If [BottomTabBarStyle](ts-container-tabcontent.md#bottomtabbarstyle9) is set, and the **vertical** attribute is **true**, the default value is the height of the **Tabs** component.<br>If **BottomTabBarStyle** is set, and the **vertical** attribute is **false**, the default value is 56 vp in versions earlier than API version 12 and 48 vp since API version 12.|
187
188### animationDuration
189
190animationDuration(value: number)
191
192Sets the length of time required to complete the tab switching animation, which is initiated by clicking a specific tab or by calling the **changeIndex** API of **TabsController**. This parameter cannot be set in percentage.
193
194**Atomic service API**: This API can be used in atomic services since API version 11.
195
196**System capability**: SystemCapability.ArkUI.ArkUI.Full
197
198**Parameters**
199
200| Name| Type  | Mandatory| Description                                                        |
201| ------ | ------ | ---- | ------------------------------------------------------------ |
202| value  | number | Yes  | Length of time required to complete the tab switching animation, which is initiated by clicking a specific tab or by calling the **changeIndex** API of **TabsController**.<br>The default value varies.<br>API version 10 and earlier versions: If this parameter is set to **null** or is not set, the default value **0** is used, which means that no tab switching animation is displayed when a specific tab is clicked or the **changeIndex** API of **TabsController** is called. If this parameter is set to **undefined** or a value less than 0, the default value **300** is used.<br>API version 11 and later versions: If this parameter is set to an invalid value or is not set, the default value is **0** when the tab bar is set to **BottomTabBarStyle** and **300** when the tab bar is set to any other style.<br>Unit: ms|
203
204### animationMode<sup>12+</sup>
205
206animationMode(mode: Optional\<AnimationMode\>)
207
208Sets the animation mode for tab switching initiated by clicking a specific tab or by calling the **changeIndex** API of **TabsController**.
209
210**Atomic service API**: This API can be used in atomic services since API version 12.
211
212**System capability**: SystemCapability.ArkUI.ArkUI.Full
213
214**Parameters**
215
216| Name| Type  | Mandatory| Description                                                        |
217| ------ | ------ | ---- | ------------------------------------------------------------ |
218| mode  | Optional\<[AnimationMode](#animationmode12)\>| Yes  | Animation mode for tab switching initiated by clicking a specific tab or by calling the **changeIndex** API of **TabsController**.<br>Default value: **AnimationMode.CONTENT_FIRST**, which means the target page content is loaded first, followed by the animation.|
219
220### barPosition<sup>9+</sup>
221
222barPosition(value: BarPosition)
223
224Sets the position of the **Tabs** component.
225
226**Atomic service API**: This API can be used in atomic services since API version 11.
227
228**System capability**: SystemCapability.ArkUI.ArkUI.Full
229
230**Parameters**
231
232| Name| Type                              | Mandatory| Description                 |
233| ----- | ---------------------------------- | ---- | -------------------- |
234| value | [BarPosition](#barposition)| Yes | Position of the **Tabs** component.<br>Default value: **BarPosition.Start**  |
235
236### divider<sup>10+</sup>
237
238divider(value: DividerStyle | null)
239
240Sets the divider between the **TabBar** and **TabContent** components.
241
242**Atomic service API**: This API can be used in atomic services since API version 11.
243
244**System capability**: SystemCapability.ArkUI.ArkUI.Full
245
246**Parameters**
247
248| Name| Type                                                     | Mandatory| Description                                                        |
249| ------ | --------------------------------------------------------- | ---- | ------------------------------------------------------------ |
250| value  | [DividerStyle](#dividerstyle10) \| null | Yes  | Divider style. By default, the divider is not displayed.<br>**DividerStyle**: divider style.<br>**null**: The divider is not displayed.|
251
252### fadingEdge<sup>10+</sup>
253
254fadingEdge(value: boolean)
255
256Sets whether the tab fades out when it exceeds the container width. It is recommended that this attribute be used together with the **barBackgroundColor** attribute. If the **barBackgroundColor** attribute is not defined, the tab fades out in white when it exceeds the container width by default.
257
258**Atomic service API**: This API can be used in atomic services since API version 11.
259
260**System capability**: SystemCapability.ArkUI.ArkUI.Full
261
262**Parameters**
263
264| Name| Type   | Mandatory| Description                                              |
265| ------ | ------- | ---- | -------------------------------------------------- |
266| value  | boolean | Yes  | Whether the tab fades out when it exceeds the container width.<br>Default value: **true**|
267
268### barOverlap<sup>10+</sup>
269
270barOverlap(value: boolean)
271
272Sets whether the tab bar is superimposed on the **TabContent** component after having its background blurred.
273
274**Atomic service API**: This API can be used in atomic services since API version 11.
275
276**System capability**: SystemCapability.ArkUI.ArkUI.Full
277
278**Parameters**
279
280| Name| Type   | Mandatory| Description                                                        |
281| ------ | ------- | ---- | ------------------------------------------------------------ |
282| value  | boolean | Yes  | Whether the tab bar is superimposed on the **TabContent** component after having its background blurred. When **barOverlap** is set to **true**, the default value of **BlurStyle** for the **TabBar** is automatically changed to **'BlurStyle.COMPONENT_THICK'**.<br>Default value: **false**|
283
284### barBackgroundColor<sup>10+</sup>
285
286barBackgroundColor(value: ResourceColor)
287
288Background color of the tab bar.
289
290**Atomic service API**: This API can be used in atomic services since API version 11.
291
292**System capability**: SystemCapability.ArkUI.ArkUI.Full
293
294**Parameters**
295
296| Name| Type                                      | Mandatory| Description                                |
297| ------ | ------------------------------------------ | ---- | ------------------------------------ |
298| value  | [ResourceColor](ts-types.md#resourcecolor) | Yes  | Background color of the tab bar.<br>Default value: **Color.Transparent**|
299
300### barBackgroundBlurStyle<sup>11+</sup>
301
302barBackgroundBlurStyle(value: BlurStyle)
303
304Sets the background blur style of the tab bar.
305
306**Atomic service API**: This API can be used in atomic services since API version 11.
307
308**System capability**: SystemCapability.ArkUI.ArkUI.Full
309
310**Parameters**
311
312| Name| Type                                        | Mandatory| Description                                    |
313| ------ | -------------------------------------------- | ---- | ---------------------------------------- |
314| value  | [BlurStyle](ts-universal-attributes-background.md#blurstyle9) | Yes  | Background blur style of the tab bar.<br>Default value: **BlurStyle.NONE**|
315
316### barGridAlign<sup>10+</sup>
317
318barGridAlign(value: BarGridColumnOptions)
319
320Sets the visible area of the tab bar in grid mode. For details, see **BarGridColumnOptions**. This attribute is effective only in horizontal mode. It is not applicable to [XS, XL, and XXL devices](../../../ui/arkts-layout-development-grid-layout.md#grid-breakpoints).
321
322**Atomic service API**: This API can be used in atomic services since API version 11.
323
324**System capability**: SystemCapability.ArkUI.ArkUI.Full
325
326**Parameters**
327
328| Name| Type                                                   | Mandatory| Description                              |
329| ------ | ------------------------------------------------------- | ---- | ---------------------------------- |
330| value  | [BarGridColumnOptions](#bargridcolumnoptions10) | Yes  | Visible area of the tab bar in grid mode.|
331
332### edgeEffect<sup>12+</sup>
333
334edgeEffect(edgeEffect: Optional&lt;EdgeEffect&gt;)
335
336Sets the edge effect used when the boundary of the scrolling area is reached.
337
338**Atomic service API**: This API can be used in atomic services since API version 12.
339
340**System capability**: SystemCapability.ArkUI.ArkUI.Full
341
342**Parameters**
343
344| Name| Type                                         | Mandatory| Description                                        |
345| ------ | --------------------------------------------- | ---- | -------------------------------------------- |
346| edgeEffect  | Optional&lt;[EdgeEffect](ts-appendix-enums.md#edgeeffect)&gt; | Yes  | Effect used when the boundary of the scrolling area is reached.<br>Default value: **EdgeEffect.Spring**|
347
348### pageFlipMode<sup>15+</sup>
349
350pageFlipMode(mode: Optional\<PageFlipMode>)
351
352Sets the mode for flipping pages using the mouse wheel.
353
354**Atomic service API**: This API can be used in atomic services since API version 15.
355
356**System capability**: SystemCapability.ArkUI.ArkUI.Full
357
358**Parameters**
359
360| Name| Type                                                       | Mandatory| Description                                                        |
361| ------ | ----------------------------------------------------------- | ---- | ------------------------------------------------------------ |
362| mode  | Optional\<[PageFlipMode](ts-appendix-enums.md#pageflipmode15)> | Yes  | Mode for flipping pages using the mouse wheel.<br>Default value: **PageFlipMode.CONTINUOUS**|
363
364## DividerStyle<sup>10+</sup>
365
366Describes the divider style.
367
368**Atomic service API**: This API can be used in atomic services since API version 11.
369
370**System capability**: SystemCapability.ArkUI.ArkUI.Full
371
372| Name         | Type                                    | Mandatory  | Description                                      |
373| ----------- | ---------------------------------------- | ---- | ---------------------------------------- |
374| strokeWidth | [Length](ts-types.md#length)             | Yes   | Width of the divider. It cannot be set in percentage.<br>Default value: **0.0**<br>Unit: vp          |
375| color       | [ResourceColor](ts-types.md#resourcecolor) | No   | Color of the divider.<br>Default value: **#33182431**               |
376| startMargin | [Length](ts-types.md#length)             | No   | Distance between the divider and the top of the sidebar. It cannot be set in percentage.<br>Default value: **0.0**<br>Unit: vp|
377| endMargin   | [Length](ts-types.md#length)             | No   | Distance between the divider and the bottom of the sidebar. It cannot be set in percentage.<br>Default value: **0.0**<br>Unit: vp|
378
379## BarGridColumnOptions<sup>10+</sup>
380
381Implements a **BarGridColumnOptions** object for setting the visible area of the tab bar in grid mode, including the column margin and gutter, as well as the number of columns occupied by tabs under small, medium, and large screen sizes.
382
383**Atomic service API**: This API can be used in atomic services since API version 11.
384
385**System capability**: SystemCapability.ArkUI.ArkUI.Full
386
387| Name         | Type                                    | Mandatory  | Description                                      |
388| ----------- | ---------------------------------------- | ---- | ---------------------------------------- |
389| margin | [Dimension](ts-types.md#dimension10)             | No   | Column margin in grid mode. It cannot be set in percentage.<br>Default value: **24.0**<br>Unit: vp                       |
390| gutter      | [Dimension](ts-types.md#dimension10) | No   | Column gutter (that is, gap between columns) in grid mode. It cannot be set in percentage.<br>Default value: **24.0**<br>Unit: vp                    |
391| sm | number            | No   | Number of columns occupied by a tab on a screen whose width is greater than or equal to 320 vp but less than 600 vp.<br>The value must be a non-negative even number. The default value is **-1**, indicating that the tab takes up the entire width of the tab bar.|
392| md   | number          | No   | Number of columns occupied by a tab on a screen whose width is greater than or equal to 600 vp but less than 800 vp.<br>The value must be a non-negative even number. The default value is **-1**, indicating that the tab takes up the entire width of the tab bar.|
393| lg   | number           | No   | Number of columns occupied by a tab on a screen whose width is greater than or equal to 840 vp but less than 1024 vp.<br>The value must be a non-negative even number. The default value is **-1**, indicating that the tab takes up the entire width of the tab bar.|
394
395## ScrollableBarModeOptions<sup>10+</sup>
396
397Implements a **ScrollableBarModeOptions** object.
398
399**Atomic service API**: This API can be used in atomic services since API version 11.
400
401**System capability**: SystemCapability.ArkUI.ArkUI.Full
402
403| Name         | Type                                    | Mandatory  | Description                                      |
404| ----------- | ---------------------------------------- | ---- | ---------------------------------------- |
405| margin | [Dimension](ts-types.md#dimension10)          | No   | Left and right margin of the tab bar in scrollable mode. It cannot be set in percentage.<br>Default value: **0.0**<br>Unit: vp                   |
406| nonScrollableLayoutStyle      | [LayoutStyle](#layoutstyle10) | No   | Tab layout mode of the tab bar when not scrolling in scrollable mode.<br>Default value: **LayoutStyle.ALWAYS_CENTER**          |
407
408## BarMode
409
410Enumerates layout modes of the tab bar.
411
412**Atomic service API**: This API can be used in atomic services since API version 11.
413
414**System capability**: SystemCapability.ArkUI.ArkUI.Full
415
416| Name       | Value| Description                                    |
417| ---------- | -- | ---------------------------------------- |
418| Scrollable | 0  | The width of each tab is determined by the actual layout. The tabs are scrollable in the following case: In horizontal layout, the total width exceeds the tab bar width; in vertical layout, the total height exceeds the tab bar height.|
419| Fixed      | 1  | The width of each tab is determined by equally dividing the number of tabs by the bar width (or bar height in the vertical layout).|
420
421## AnimationMode<sup>12+</sup>
422
423Enumerates the animation modes for switching between tabs.
424
425**System capability**: SystemCapability.ArkUI.ArkUI.Full
426
427| Name         | Value  | Description                                                        |
428| ------------- | ---- | ------------------------------------------------------------ |
429| CONTENT_FIRST | 0    | Load the content of the target page before starting the switching animation.<br>**Atomic service API**: This API can be used in atomic services since API version 12.|
430| ACTION_FIRST  | 1    | Start the switching animation before loading the content of the target page. For the settings to take effect, the height and width of tabs must be set to **auto**.<br>**Atomic service API**: This API can be used in atomic services since API version 12.|
431| NO_ANIMATION  | 2    | Disable the default switching animation. This value is ineffective when **TabContent** is switched using the **changeIndex** API of **TabsController**.<br>To disable the animation under this scenario, set **animationDuration** to **0**.<br>**Atomic service API**: This API can be used in atomic services since API version 12.|
432| CONTENT_FIRST_WITH_JUMP<sup>15+</sup> | 3    | Load the content of the target page first, then jump to the vicinity of the target page without animation, and finally jump to the target page with animation.<br>**Atomic service API**: This API can be used in atomic services since API version 15.|
433| ACTION_FIRST_WITH_JUMP<sup>15+</sup>  | 4    | Jump to the vicinity of the target page without animation first, then jump to the target page with animation, and finally load the content of the target page. For the settings to take effect, the height and width of tabs must be set to **auto**.<br>**Atomic service API**: This API can be used in atomic services since API version 15.|
434
435## LayoutStyle<sup>10+</sup>
436
437Enumerates the tab layout styles of the tab bar when not scrolling in scrollable mode.
438
439**Atomic service API**: This API can be used in atomic services since API version 11.
440
441**System capability**: SystemCapability.ArkUI.ArkUI.Full
442
443| Name        | Value| Description                                    |
444| ---------- | -- | ---------------------------------------- |
445| ALWAYS_CENTER | 0 | If the tab content exceeds the tab bar width, the tabs are scrollable.<br>If not, the tabs are compactly centered on the tab bar and not scrollable.|
446| ALWAYS_AVERAGE_SPLIT | 1 | If the tab content exceeds the tab bar width, the tabs are scrollable.<br>If not, the tabs are not scrollable, and the width of the tab bar is evenly distributed among all tabs.|
447| SPACE_BETWEEN_OR_CENTER      | 2 | If the tab content exceeds the tab bar width, the tabs are scrollable.<br>If the tab content exceeds half the width of the tab bar but is still within the tab bar width, the tabs are compactly centered and not scrollable.<br>If the tab content does not exceed half the width of the tab bar, the tabs are centered within half the width of the tab bar with even spacing between them and are not scrollable.|
448
449## CommonModifier<sup>15+</sup>
450
451type CommonModifier = CommonModifier
452
453Defines a parameter object for the **Tabs** component.
454
455**Atomic service API**: This API can be used in atomic services since API version 15.
456
457**System capability**: SystemCapability.ArkUI.ArkUI.Full
458
459| Type        | Description                                    |
460| ---------- | ---------------------------------------- |
461| [CommonModifier](ts-universal-attributes-attribute-modifier.md#attributemodifier) | Universal attributes for the tab bar.|
462
463## Events
464
465In addition to the [universal events](ts-component-general-events.md), the following events are supported.
466
467### onChange
468
469onChange(event: (index: number) =&gt; void)
470
471Triggered when a tab is switched.
472
473This event is triggered when any of the following conditions is met:
474
4751. The swiping animation is completed, followed by tab switching.
476
4772. The [Controller](#tabscontroller) API is called.
478
4793. The attribute value is updated using a [state variable](../../../quick-start/arkts-state.md).
480
4814. A tab is clicked.
482
483>  **NOTE**
484>
485>  When a custom tab is used, the synchronization between tabs and swipe gestures in the **onChange** event may be performed only after tab switching occurs. This can lead to a delay in switching to the custom tab. To address this issue, listen for the current tab index in [onAnimationStart](#onanimationstart11) and update the tab index accordingly. For details about the implementation, see [Example 1](#example-1-setting-up-custom-tab-switching-synchronization).
486
487**Atomic service API**: This API can be used in atomic services since API version 11.
488
489**System capability**: SystemCapability.ArkUI.ArkUI.Full
490
491**Parameters**
492
493| Name| Type  | Mandatory| Description                                |
494| ------ | ------ | ---- | ------------------------------------ |
495| index  | number | Yes  | Index of the clicked tab. The index starts from 0.|
496
497### onTabBarClick<sup>10+</sup>
498
499onTabBarClick(event: (index: number) =&gt; void)
500
501Triggered when a tab is clicked.
502
503**Atomic service API**: This API can be used in atomic services since API version 11.
504
505**System capability**: SystemCapability.ArkUI.ArkUI.Full
506
507**Parameters**
508
509| Name| Type  | Mandatory| Description                                |
510| ------ | ------ | ---- | ------------------------------------ |
511| event  | [Callback](./ts-types.md#callback12)\<number> | Yes  | Index of the clicked tab. The index starts from 0.|
512
513### onAnimationStart<sup>11+</sup>
514
515onAnimationStart(handler: OnTabsAnimationStartCallback)
516
517Triggered when the tab switching animation starts. This callback is not triggered when **animationDuration** is set to **0**, which effectively disables the animation.
518
519**Atomic service API**: This API can be used in atomic services since API version 12.
520
521**System capability**: SystemCapability.ArkUI.ArkUI.Full
522
523**Parameters**
524
525| Name     | Type                                                  | Mandatory| Description                                                        |
526| ----------- | ------------------------------------------------------ | ---- | ------------------------------------------------------------ |
527| index       | number                                                 | Yes  | Index of the currently displayed element.                                        |
528| targetIndex | number                                                 | Yes  | Index of the target element to switch to.                                    |
529| event       | [TabsAnimationEvent](#tabsanimationevent11) | Yes  | Extra information of the animation, including the offset of the currently displayed element and target element relative to the start position of the **Tabs** along the main axis, and the hands-off velocity.|
530
531### onAnimationEnd<sup>11+</sup>
532
533onAnimationEnd(handler: (index: number, event: TabsAnimationEvent) => void)
534
535Triggered when the tab switching animation ends. This event is triggered when the tab switching animation ends, whether it is caused by gesture interruption or not. This callback is not triggered when **animationDuration** is set to **0**, which effectively disables the animation.
536
537**Atomic service API**: This API can be used in atomic services since API version 12.
538
539**System capability**: SystemCapability.ArkUI.ArkUI.Full
540
541**Parameters**
542
543| Name| Type                                                  | Mandatory| Description                                                        |
544| ------ | ------------------------------------------------------ | ---- | ------------------------------------------------------------ |
545| index  | number                                                 | Yes  | Index of the currently displayed element.                                        |
546| event  | [TabsAnimationEvent](#tabsanimationevent11) | Yes  | Extra information of the animation, which is the offset of the currently displayed element relative to the start position of the **Tabs** along the main axis.|
547
548### onGestureSwipe<sup>11+</sup>
549
550onGestureSwipe(handler: (index: number, event: TabsAnimationEvent) => void)
551
552Triggered on a frame-by-frame basis when the tab is switched by a swipe.
553
554**Atomic service API**: This API can be used in atomic services since API version 12.
555
556**System capability**: SystemCapability.ArkUI.ArkUI.Full
557
558**Parameters**
559
560| Name| Type                                                  | Mandatory| Description                                                        |
561| ------ | ------------------------------------------------------ | ---- | ------------------------------------------------------------ |
562| index  | number                                                 | Yes  | Index of the currently displayed element.                                        |
563| event  | [TabsAnimationEvent](#tabsanimationevent11) | Yes  | Extra information of the animation, which is the offset of the currently displayed element relative to the start position of the **Tabs** along the main axis.|
564
565### customContentTransition<sup>11+</sup>
566
567customContentTransition(delegate: (from: number, to: number) => TabContentAnimatedTransition \| undefined)
568
569Sets the custom tab switching animation.
570
571Instructions:
572
5731. When the custom tab switching animation is used, the default switching animation of the **Tabs** component is disabled, and tabs cannot be switched through swiping.<br>2. The value **undefined** means not to use the custom tab switching animation, in which case the default switching animation is used.<br>3. The custom tab switching animation cannot be interrupted.<br>4. Currently, the custom tab switching animation can be triggered only by clicking a tab or by calling the **TabsController.changeIndex()** API.<br>5. When the custom tab switching animation is used, the **Tabs** component supports all events except **onGestureSwipe**.<br>6. Notes about the **onChange** and **onAnimationEnd** events: If the second custom animation is triggered during the execution of the first custom animation, the **onChange** and **onAnimationEnd** events of the first custom animation will be triggered when the second custom animation starts.<br>7. When the custom animation is used, the stack layout is used for pages involved in the animation. If the **zIndex** attribute is not set for related pages, the **zIndex** values of all pages are the same. In this case, the pages are rendered in the order in which they are added to the component tree (that is, the sequence of page indexes). In light of this, to control the rendering levels of pages, set the **zIndex** attribute of the pages.
574
575**Widget capability**: This API can be used in ArkTS widgets since API version 11.
576
577**Atomic service API**: This API can be used in atomic services since API version 12.
578
579**System capability**: SystemCapability.ArkUI.ArkUI.Full
580
581**Parameters**
582
583| Name| Type  | Mandatory| Description                           |
584| ------ | ------ | ---- | ------------------------------- |
585| from   | number | Yes  | Index of the currently displayed tab before the animation starts.|
586| to     | number | Yes  | Index of the target tab before the animation starts.|
587
588**Return value**
589
590| Type                                                        | Description                    |
591| ------------------------------------------------------------ | ------------------------ |
592| [TabContentAnimatedTransition](#tabcontentanimatedtransition11) \| undefined | Information about the custom tab switching animation.|
593
594### onContentWillChange<sup>12+</sup>
595
596onContentWillChange(handler: (currentIndex: number, comingIndex: number) => boolean)
597
598Triggered when a new page is about to be displayed.
599
600Specifically, this event is triggered in the following cases:
601
6021. When the user swipes on the **TabContent** component (provided that it supports swiping) to switch to a new page.
603
6042. When **TabsController.changeIndex** is called to switch to a new page.
605
6063. When the **index** attribute is changed to switch to a new page.
607
6084. When the user clicks a tab on the tab bar to switch to a new page.
609
6105. When the user presses the left or right arrow key on the keyboard to switch to a new page while the tab bar is focused.
611
612**Atomic service API**: This API can be used in atomic services since API version 12.
613
614**System capability**: SystemCapability.ArkUI.ArkUI.Full
615
616**Parameters**
617
618| Name      | Type  | Mandatory| Description                                      |
619| ------------ | ------ | ---- | ------------------------------------------ |
620| currentIndex | number | Yes  | Index of the active tab. The index starts from 0.|
621| comingIndex  | number | Yes  | Index of the new tab to be displayed.             |
622
623**Return value**
624
625| Type   | Description                                                        |
626| ------- | ------------------------------------------------------------ |
627| boolean | The value **true** means that the tab can switch to the new page.<br>The value **false** means that the tab cannot switch to the new page and will remain on the current page.|
628
629## TabsAnimationEvent<sup>11+</sup>
630
631Describes the animation information of the **Tabs** component.
632
633**Atomic service API**: This API can be used in atomic services since API version 12.
634
635**System capability**: SystemCapability.ArkUI.ArkUI.Full
636
637| Name           | Type     | Read Only| Optional| Description                                      |
638| ------------- | ---------- | ---- | ---- | ------------------------ |
639| currentOffset | number | No| No| Offset of the currently displayed element relative to the start position of the **Tabs** component along the main axis.<br> Unit: vp<br>Default value: **0**|
640| targetOffset | number | No| No| Offset of the target element relative to the start position of the **Tabs** component along the main axis.<br> Unit: vp<br>Default value: **0**|
641| velocity | number | No| No| Hands-off velocity at the beginning of the animation. Unit: VP/S<br>Default value: **0**|
642
643## TabContentAnimatedTransition<sup>11+</sup>
644
645Provides the information about the custom tab page switching animation.
646
647**Widget capability**: This API can be used in ArkTS widgets since API version 11.
648
649**Atomic service API**: This API can be used in atomic services since API version 12.
650
651**System capability**: SystemCapability.ArkUI.ArkUI.Full
652
653| Name           | Type        | Mandatory  | Description                                      |
654| ------------- | ---------------------- | ---- |---------------------- |
655| timeout | number | No| Timeout for the custom switching animation. The timer starts when the switching begins. If this timeframe passes without you calling the **finishTransition** API in [TabContentTransitionProxy](#tabcontenttransitionproxy11), the component will assume that the custom animation has ended and will proceed directly with subsequent operations. Unit: ms<br>Default value: **1000**|
656| transition | [Callback](./ts-types.md#callback12)\<[TabContentTransitionProxy](#tabcontenttransitionproxy11)> | Yes| Content of the custom switching animation.|
657
658## TabContentTransitionProxy<sup>11+</sup>
659
660Implements the proxy object returned during the execution of the custom switching animation of the **Tabs** component. You can use this object to obtain the start and target pages for the custom tab switching animation. In addition, you can call the **finishTransition** API of this object to notify the **Tabs** component of the ending of the custom animation.
661
662**Widget capability**: This API can be used in ArkTS widgets since API version 11.
663
664**Atomic service API**: This API can be used in atomic services since API version 12.
665
666**System capability**: SystemCapability.ArkUI.ArkUI.Full
667
668### Attributes
669
670| Name | Type    | Read Only| Optional| Description                        |
671| ----- | ------- | ---- | ---- | --------------------------- |
672| from | number | No| No| Index of the starting page of the custom animation.|
673| to | number | No| No| Index of the target tab to switch to.|
674
675### finishTransition
676
677finishTransition(): void
678
679Notifies the **Tabs** component that the custom animation has finished playing.
680
681**Widget capability**: This API can be used in ArkTS widgets since API version 11.
682
683**Atomic service API**: This API can be used in atomic services since API version 12.
684
685**System capability**: SystemCapability.ArkUI.ArkUI.Full
686
687## TabsController
688
689Defines a tab controller, which is used to control switching of tabs. One **TabsController** cannot control multiple **Tabs** components.
690
691**Atomic service API**: This API can be used in atomic services since API version 11.
692
693**System capability**: SystemCapability.ArkUI.ArkUI.Full
694
695### Objects to Import
696
697```ts
698let controller: TabsController = new TabsController()
699```
700
701### constructor
702
703constructor()
704
705A constructor used to create a **TabsController** object.
706
707**Atomic service API**: This API can be used in atomic services since API version 11.
708
709**System capability**: SystemCapability.ArkUI.ArkUI.Full
710
711### changeIndex
712
713changeIndex(value: number): void
714
715Switches to the specified tab.
716
717**Atomic service API**: This API can be used in atomic services since API version 11.
718
719**System capability**: SystemCapability.ArkUI.ArkUI.Full
720
721**Parameters**
722
723| Name  | Type  | Mandatory  | Description                                    |
724| ----- | ------ | ---- | ---------------------------------------- |
725| value | number | Yes   | Index of the tab. The value starts from 0.<br>**NOTE**<br>If this parameter is set to a value less than 0 or greater than the maximum number, the default value **0** is used.|
726
727### preloadItems<sup>12+</sup>
728
729preloadItems(indices: Optional\<Array\<number>>): Promise\<void>
730
731Preloads child nodes. After this API is called, all specified child nodes will be loaded at once. Therefore, for performance considerations, it is recommended that you load child nodes in batches.
732
733**Atomic service API**: This API can be used in atomic services since API version 12.
734
735**System capability**: SystemCapability.ArkUI.ArkUI.Full
736
737**Parameters**
738
739| Name  | Type  | Mandatory  | Description                                    |
740| ----- | ------ | ---- | ---------------------------------------- |
741| indices | Optional\<Array\<number>> | Yes| Array of indexes of the child nodes to preload.<br>The default value is an empty array.|
742
743**Return value**
744
745| Type                                                        | Description                    |
746| ------------------------------------------------------------ | ------------------------ |
747| Promise\<void> | Promise used to return the value.|
748
749**Error codes**
750
751For details about the error codes, see [Universal Error Codes](../../errorcode-universal.md).
752
753| ID  | Error Message                                     |
754| --------   | -------------------------------------------- |
755| 401 | Parameter invalid. Possible causes: 1. The parameter type is not Array\<number>; 2. The parameter is an empty array; 3. The parameter contains an invalid index. |
756
757### setTabBarTranslate<sup>13+</sup>
758
759setTabBarTranslate(translate: TranslateOptions): void
760
761Sets the translation distance of the tab bar.
762
763> **NOTE**
764>
765> When **bindTabsToScrollable** or **bindTabsToNestedScrollable** is used to bind the **Tabs** component with a scrollable container, scrolling the container will trigger the display and hide animations of the tab bar for all **Tabs** components bound to it. In this case, calling the **setTabBarTranslate** API has no effect. Therefore, avoid using **bindTabsToScrollable**, **bindTabsToNestedScrollable**, and **setTabBarTranslate** simultaneously.
766>
767
768**Atomic service API**: This API can be used in atomic services since API version 13.
769
770**System capability**: SystemCapability.ArkUI.ArkUI.Full
771
772**Parameters**
773
774| Name  | Type  | Mandatory  | Description                                    |
775| ----- | ------ | ---- | ---------------------------------------- |
776| translate | [TranslateOptions](ts-universal-attributes-transformation.md#translateoptions) | Yes| Translation distance of the tab bar.|
777
778### setTabBarOpacity<sup>13+</sup>
779
780setTabBarOpacity(opacity: number): void
781
782Sets the opacity of the tab bar.
783
784> **NOTE**
785>
786> When **bindTabsToScrollable** or **bindTabsToNestedScrollable** is used to bind the **Tabs** component with a scrollable container, scrolling the container will trigger the display and hide animations of the tab bar for all **Tabs** components bound to it. In this case, calling the **setTabBarOpacity** API has no effect. Therefore, avoid using **bindTabsToScrollable**, **bindTabsToNestedScrollable**, and **setTabBarOpacity** simultaneously.
787>
788
789**Atomic service API**: This API can be used in atomic services since API version 13.
790
791**System capability**: SystemCapability.ArkUI.ArkUI.Full
792
793**Parameters**
794
795| Name  | Type  | Mandatory  | Description                                    |
796| ----- | ------ | ---- | ---------------------------------------- |
797| opacity | number | Yes| Opacity of the tab bar. The value range is [0.0, 1.0].|
798
799## Example
800
801### Example 1: Setting Up Custom Tab Switching Synchronization
802
803This example demonstrates how to use **onAnimationStart** and **onChange** to synchronize tabs with swiping gestures during tab switching.
804
805```ts
806// xxx.ets
807@Entry
808@Component
809struct TabsExample {
810  @State fontColor: string = '#182431'
811  @State selectedFontColor: string = '#007DFF'
812  @State currentIndex: number = 0
813  @State selectedIndex: number = 0
814  private controller: TabsController = new TabsController()
815
816  @Builder tabBuilder(index: number, name: string) {
817    Column() {
818      Text(name)
819        .fontColor(this.selectedIndex === index ? this.selectedFontColor : this.fontColor)
820        .fontSize(16)
821        .fontWeight(this.selectedIndex === index ? 500 : 400)
822        .lineHeight(22)
823        .margin({ top: 17, bottom: 7 })
824      Divider()
825        .strokeWidth(2)
826        .color('#007DFF')
827        .opacity(this.selectedIndex === index ? 1 : 0)
828    }.width('100%')
829  }
830
831  build() {
832    Column() {
833      Tabs({ barPosition: BarPosition.Start, index: this.currentIndex, controller: this.controller }) {
834        TabContent() {
835          Column().width('100%').height('100%').backgroundColor('#00CB87')
836        }.tabBar(this.tabBuilder(0, 'green'))
837
838        TabContent() {
839          Column().width('100%').height('100%').backgroundColor('#007DFF')
840        }.tabBar(this.tabBuilder(1, 'blue'))
841
842        TabContent() {
843          Column().width('100%').height('100%').backgroundColor('#FFBF00')
844        }.tabBar(this.tabBuilder(2, 'yellow'))
845
846        TabContent() {
847          Column().width('100%').height('100%').backgroundColor('#E67C92')
848        }.tabBar(this.tabBuilder(3, 'pink'))
849      }
850      .vertical(false)
851      .barMode(BarMode.Fixed)
852      .barWidth(360)
853      .barHeight(56)
854      .animationDuration(400)
855      .onChange((index: number) => {
856        // currentIndex controls which tab is displayed.
857        this.currentIndex = index
858        this.selectedIndex = index
859      })
860      .onAnimationStart((index: number, targetIndex: number, event: TabsAnimationEvent) => {
861        if (index === targetIndex) {
862          return
863        }
864        // selectedIndex controls the color switching for the image and text in the custom tab bar.
865        this.selectedIndex = targetIndex
866      })
867      .width(360)
868      .height(296)
869      .margin({ top: 52 })
870      .backgroundColor('#F1F3F5')
871    }.width('100%')
872  }
873}
874```
875
876![tabs2](figures/tabs2.gif)
877
878### Example 2: Setting the Basic Attributes of the Divider
879
880This example uses **divider** to present dividers in different styles.
881
882```ts
883// xxx.ets
884@Entry
885@Component
886struct TabsDivider1 {
887  private controller1: TabsController = new TabsController()
888  @State dividerColor: string = 'red'
889  @State strokeWidth: number = 2
890  @State startMargin: number = 0
891  @State endMargin: number = 0
892  @State nullFlag: boolean = false
893
894  build() {
895    Column() {
896      Tabs({ controller: this.controller1 }) {
897        TabContent() {
898          Column().width('100%').height('100%').backgroundColor(Color.Pink)
899        }.tabBar('pink')
900
901        TabContent() {
902          Column().width('100%').height('100%').backgroundColor(Color.Yellow)
903        }.tabBar('yellow')
904
905        TabContent() {
906          Column().width('100%').height('100%').backgroundColor(Color.Blue)
907        }.tabBar('blue')
908
909        TabContent() {
910          Column().width('100%').height('100%').backgroundColor(Color.Green)
911        }.tabBar('green')
912
913        TabContent() {
914          Column().width('100%').height('100%').backgroundColor(Color.Red)
915        }.tabBar('red')
916      }
917      .vertical(true)
918      .scrollable(true)
919      .barMode(BarMode.Fixed)
920      .barWidth(70)
921      .barHeight(200)
922      .animationDuration(400)
923      .onChange((index: number) => {
924        console.info(index.toString())
925      })
926      .height('200vp')
927      .margin({ bottom: '12vp' })
928      .divider(this.nullFlag ? null : {
929        strokeWidth: this.strokeWidth,
930        color: this.dividerColor,
931        startMargin: this.startMargin,
932        endMargin: this.endMargin
933      })
934
935      Button('Regular Divider').width('100%').margin({ bottom: '12vp' })
936        .onClick(() => {
937          this.nullFlag = false;
938          this.strokeWidth = 2;
939          this.dividerColor = 'red';
940          this.startMargin = 0;
941          this.endMargin = 0;
942        })
943      Button('Empty Divider').width('100%').margin({ bottom: '12vp' })
944        .onClick(() => {
945          this.nullFlag = true
946        })
947      Button('Change to Blue').width('100%').margin({ bottom: '12vp'})
948        .onClick(() => {
949          this.dividerColor = 'blue'
950        })
951      Button('Increase Width').width('100%').margin({ bottom: '12vp' })
952        .onClick(() => {
953          this.strokeWidth += 2
954        })
955      Button('Decrease Width').width('100%').margin({ bottom: '12vp'})
956        .onClick(() => {
957          if (this.strokeWidth > 2) {
958            this.strokeWidth -= 2
959          }
960        })
961      Button('Increase Top Margin').width('100%').margin({ bottom: '12vp' })
962        .onClick(() => {
963          this.startMargin += 2
964        })
965      Button('Decrease Top Margin').width('100%').margin({ bottom: '12vp' })
966        .onClick(() => {
967          if (this.startMargin > 2) {
968            this.startMargin -= 2
969          }
970        })
971      Button('Increase Bottom Margin').width('100%').margin({ bottom:'12vp'})
972        .onClick(() => {
973          this.endMargin += 2
974        })
975      Button('Decrease Bottom Margin').width('100%').margin({ bottom:'12vp' })
976        .onClick(() => {
977          if (this.endMargin > 2) {
978            this.endMargin -= 2
979          }
980        })
981    }.padding({ top: '24vp', left: '24vp', right: '24vp' })
982  }
983}
984```
985
986![tabs3](figures/tabs3.gif)
987
988### Example 3: Setting Tab Bar Fading
989
990This example uses **fadingEdge** to specify whether to fade out tabs.
991
992```ts
993// xxx.ets
994@Entry
995@Component
996struct TabsOpaque {
997  @State message: string = 'Hello World'
998  private controller: TabsController = new TabsController()
999  private controller1: TabsController = new TabsController()
1000  @State selfFadingFade: boolean = true;
1001
1002  build() {
1003    Column() {
1004      Button('Set Tab to Fade').width('100%').margin({ bottom: '12vp' })
1005        .onClick((event?: ClickEvent) => {
1006          this.selfFadingFade = true;
1007        })
1008      Button('Set Tab Not to Fade').width('100%').margin({ bottom: '12vp' })
1009        .onClick((event?: ClickEvent) => {
1010          this.selfFadingFade = false;
1011        })
1012      Tabs({ barPosition: BarPosition.End, controller: this.controller }) {
1013        TabContent() {
1014          Column().width('100%').height('100%').backgroundColor(Color.Pink)
1015        }.tabBar('pink')
1016
1017        TabContent() {
1018          Column().width('100%').height('100%').backgroundColor(Color.Yellow)
1019        }.tabBar('yellow')
1020
1021        TabContent() {
1022          Column().width('100%').height('100%').backgroundColor(Color.Blue)
1023        }.tabBar('blue')
1024
1025        TabContent() {
1026          Column().width('100%').height('100%').backgroundColor(Color.Green)
1027        }.tabBar('green')
1028
1029        TabContent() {
1030          Column().width('100%').height('100%').backgroundColor(Color.Green)
1031        }.tabBar('green')
1032
1033        TabContent() {
1034          Column().width('100%').height('100%').backgroundColor(Color.Green)
1035        }.tabBar('green')
1036
1037        TabContent() {
1038          Column().width('100%').height('100%').backgroundColor(Color.Green)
1039        }.tabBar('green')
1040
1041        TabContent() {
1042          Column().width('100%').height('100%').backgroundColor(Color.Green)
1043        }.tabBar('green')
1044      }
1045      .vertical(false)
1046      .scrollable(true)
1047      .barMode(BarMode.Scrollable)
1048      .barHeight(80)
1049      .animationDuration(400)
1050      .onChange((index: number) => {
1051        console.info(index.toString())
1052      })
1053      .fadingEdge(this.selfFadingFade)
1054      .height('30%')
1055      .width('100%')
1056
1057      Tabs({ barPosition: BarPosition.Start, controller: this.controller1 }) {
1058        TabContent() {
1059          Column().width('100%').height('100%').backgroundColor(Color.Pink)
1060        }.tabBar('pink')
1061
1062        TabContent() {
1063          Column().width('100%').height('100%').backgroundColor(Color.Yellow)
1064        }.tabBar('yellow')
1065
1066        TabContent() {
1067          Column().width('100%').height('100%').backgroundColor(Color.Blue)
1068        }.tabBar('blue')
1069
1070        TabContent() {
1071          Column().width('100%').height('100%').backgroundColor(Color.Green)
1072        }.tabBar('green')
1073
1074        TabContent() {
1075          Column().width('100%').height('100%').backgroundColor(Color.Green)
1076        }.tabBar('green')
1077
1078        TabContent() {
1079          Column().width('100%').height('100%').backgroundColor(Color.Green)
1080        }.tabBar('green')
1081      }
1082      .vertical(true)
1083      .scrollable(true)
1084      .barMode(BarMode.Scrollable)
1085      .barHeight(200)
1086      .barWidth(80)
1087      .animationDuration(400)
1088      .onChange((index: number) => {
1089        console.info(index.toString())
1090      })
1091      .fadingEdge(this.selfFadingFade)
1092      .height('30%')
1093      .width('100%')
1094    }
1095    .padding({ top: '24vp', left: '24vp', right: '24vp' })
1096  }
1097}
1098```
1099
1100![tabs4](figures/tabs4.gif)
1101
1102### Example 4: Setting the Tab Bar to Be Superimposed on the TabContent Component
1103
1104This example uses **barOverlap** to specify whether the tab bar is superimposed on the **TabContent** component after having its background blurred.
1105
1106```ts
1107// xxx.ets
1108@Entry
1109@Component
1110struct barHeightTest {
1111  @State arr: number[] = [0, 1, 2, 3]
1112  @State barOverlap: boolean = true;
1113  build() {
1114    Column() {
1115      Text(`barOverlap ${this.barOverlap}`).fontSize(16)
1116      Button("Change barOverlap").width('100%').margin({ bottom: '12vp' })
1117        .onClick((event?: ClickEvent) => {
1118          if (this.barOverlap) {
1119            this.barOverlap = false;
1120          } else {
1121            this.barOverlap = true;
1122          }
1123        })
1124
1125      Tabs({ barPosition: BarPosition.End }) {
1126        TabContent() {
1127          Column() {
1128            List({ space: 10 }) {
1129              ForEach(this.arr, (item: number) => {
1130                ListItem() {
1131                  Text("item" + item).width('80%').height(200).fontSize(16).textAlign(TextAlign.Center).backgroundColor('#fff8b81e')
1132                }
1133              }, (item: string) => item)
1134            }.width('100%').height('100%')
1135            .lanes(2).alignListItem(ListItemAlign.Center)
1136          }.width('100%').height('100%')
1137          .backgroundColor(Color.Pink)
1138        }
1139        .tabBar(new BottomTabBarStyle($r('sys.media.ohos_icon_mask_svg'), "test 0"))
1140      }
1141      .scrollable(false)
1142      .height('60%')
1143      .barOverlap(this.barOverlap)
1144    }
1145    .height(500)
1146    .padding({ top: '24vp', left: '24vp', right: '24vp' })
1147  }
1148}
1149```
1150
1151![tabs5](figures/tabs5.gif)
1152
1153### Example 5: Setting the Grid-Aligned Visible Area for the TabBar
1154
1155This example uses **barGridAlign** to set the visible area of the tab bar in grid mode.
1156
1157```ts
1158// xxx.ets
1159@Entry
1160@Component
1161struct TabsExample5 {
1162  private controller: TabsController = new TabsController()
1163  @State gridMargin: number = 10
1164  @State gridGutter: number = 10
1165  @State sm: number = -2
1166  @State clickedContent: string = "";
1167
1168  build() {
1169    Column() {
1170      Row() {
1171        Button("gridMargin+10 " + this.gridMargin)
1172          .width('47%')
1173          .height(50)
1174          .margin({ top: 5 })
1175          .onClick((event?: ClickEvent) => {
1176            this.gridMargin += 10
1177          })
1178          .margin({ right: '6%', bottom: '12vp' })
1179        Button("gridMargin-10 " + this.gridMargin)
1180          .width('47%')
1181          .height(50)
1182          .margin({ top: 5 })
1183          .onClick((event?: ClickEvent) => {
1184            this.gridMargin -= 10
1185          })
1186          .margin({ bottom: '12vp' })
1187      }
1188
1189      Row() {
1190        Button("gridGutter+10 " + this.gridGutter)
1191          .width('47%')
1192          .height(50)
1193          .margin({ top: 5 })
1194          .onClick((event?: ClickEvent) => {
1195            this.gridGutter += 10
1196          })
1197          .margin({ right: '6%', bottom: '12vp' })
1198        Button("gridGutter-10 " + this.gridGutter)
1199          .width('47%')
1200          .height(50)
1201          .margin({ top: 5 })
1202          .onClick((event?: ClickEvent) => {
1203            this.gridGutter -= 10
1204          })
1205          .margin({ bottom: '12vp' })
1206      }
1207
1208      Row() {
1209        Button("sm+2 " + this.sm)
1210          .width('47%')
1211          .height(50)
1212          .margin({ top: 5 })
1213          .onClick((event?: ClickEvent) => {
1214            this.sm += 2
1215          })
1216          .margin({ right: '6%' })
1217        Button("sm-2 " + this.sm).width('47%').height(50).margin({ top: 5 })
1218          .onClick((event?: ClickEvent) => {
1219            this.sm -= 2
1220          })
1221      }
1222
1223      Text("Clicked content: " + this.clickedContent).width('100%').height(200).margin({ top: 5 })
1224
1225
1226      Tabs({ barPosition: BarPosition.End, controller: this.controller }) {
1227        TabContent() {
1228          Column().width('100%').height('100%').backgroundColor(Color.Pink)
1229        }.tabBar(BottomTabBarStyle.of($r("sys.media.ohos_app_icon"), "1"))
1230
1231        TabContent() {
1232          Column().width('100%').height('100%').backgroundColor(Color.Green)
1233        }.tabBar(BottomTabBarStyle.of($r("sys.media.ohos_app_icon"), "2"))
1234
1235        TabContent() {
1236          Column().width('100%').height('100%').backgroundColor(Color.Blue)
1237        }.tabBar(BottomTabBarStyle.of($r("sys.media.ohos_app_icon"), "3"))
1238      }
1239      .width('350vp')
1240      .animationDuration(300)
1241      .height('60%')
1242      .barGridAlign({ sm: this.sm, margin: this.gridMargin, gutter: this.gridGutter })
1243      .backgroundColor(0xf1f3f5)
1244      .onTabBarClick((index: number) => {
1245        this.clickedContent += "index " + index + " was clicked\n";
1246      })
1247    }
1248    .width('100%')
1249    .height(500)
1250    .margin({ top: 5 })
1251    .padding('10vp')
1252  }
1253}
1254```
1255
1256![tabs5](figures/tabs6.gif)
1257
1258### Example 6: Setting the Layout Style for a Scrollable TabBar
1259
1260This example implements the **ScrollableBarModeOptions** parameter of **barMode**. This parameter is effective only in **Scrollable** mode.
1261
1262```ts
1263// xxx.ets
1264@Entry
1265@Component
1266struct TabsExample6 {
1267  private controller: TabsController = new TabsController()
1268  @State scrollMargin: number = 0
1269  @State layoutStyle: LayoutStyle = LayoutStyle.ALWAYS_CENTER
1270  @State text: string = "Text"
1271
1272  build() {
1273    Column() {
1274      Row() {
1275        Button("scrollMargin+10 " + this.scrollMargin)
1276          .width('47%')
1277          .height(50)
1278          .margin({ top: 5 })
1279          .onClick((event?: ClickEvent) => {
1280            this.scrollMargin += 10
1281          })
1282          .margin({ right: '6%', bottom: '12vp' })
1283        Button("scrollMargin-10 " + this.scrollMargin)
1284          .width('47%')
1285          .height(50)
1286          .margin({ top: 5 })
1287          .onClick((event?: ClickEvent) => {
1288            this.scrollMargin -= 10
1289          })
1290          .margin({ bottom: '12vp' })
1291      }
1292
1293      Row() {
1294        Button("Add Text")
1295          .width('47%')
1296          .height(50)
1297          .margin({ top: 5 })
1298          .onClick((event?: ClickEvent) => {
1299            this.text += 'Add Text'
1300          })
1301          .margin({ right: '6%', bottom: '12vp' })
1302        Button("Reset Text")
1303          .width('47%')
1304          .height(50)
1305          .margin({ top: 5 })
1306          .onClick((event?: ClickEvent) => {
1307            this.text = "Text"
1308          })
1309          .margin({ bottom: '12vp' })
1310      }
1311
1312      Row() {
1313        Button("layoutStyle.ALWAYS_CENTER")
1314          .width('100%')
1315          .height(50)
1316          .margin({ top: 5 })
1317          .fontSize(15)
1318          .onClick((event?: ClickEvent) => {
1319            this.layoutStyle = LayoutStyle.ALWAYS_CENTER;
1320          })
1321          .margin({ bottom: '12vp' })
1322      }
1323
1324      Row() {
1325        Button("layoutStyle.ALWAYS_AVERAGE_SPLIT")
1326          .width('100%')
1327          .height(50)
1328          .margin({ top: 5 })
1329          .fontSize(15)
1330          .onClick((event?: ClickEvent) => {
1331            this.layoutStyle = LayoutStyle.ALWAYS_AVERAGE_SPLIT;
1332          })
1333          .margin({ bottom: '12vp' })
1334      }
1335
1336      Row() {
1337        Button("layoutStyle.SPACE_BETWEEN_OR_CENTER")
1338          .width('100%')
1339          .height(50)
1340          .margin({ top: 5 })
1341          .fontSize(15)
1342          .onClick((event?: ClickEvent) => {
1343            this.layoutStyle = LayoutStyle.SPACE_BETWEEN_OR_CENTER;
1344          })
1345          .margin({ bottom: '12vp' })
1346      }
1347
1348      Tabs({ barPosition: BarPosition.End, controller: this.controller }) {
1349        TabContent() {
1350          Column().width('100%').height('100%').backgroundColor(Color.Pink)
1351        }.tabBar(SubTabBarStyle.of(this.text))
1352
1353        TabContent() {
1354          Column().width('100%').height('100%').backgroundColor(Color.Green)
1355        }.tabBar(SubTabBarStyle.of(this.text))
1356
1357        TabContent() {
1358          Column().width('100%').height('100%').backgroundColor(Color.Blue)
1359        }.tabBar(SubTabBarStyle.of(this.text))
1360      }
1361      .animationDuration(300)
1362      .height('60%')
1363      .backgroundColor(0xf1f3f5)
1364      .barMode(BarMode.Scrollable, { margin: this.scrollMargin, nonScrollableLayoutStyle: this.layoutStyle })
1365    }
1366    .width('100%')
1367    .height(500)
1368    .margin({ top: 5 })
1369    .padding('24vp')
1370  }
1371}
1372```
1373
1374![tabs5](figures/tabs7.gif)
1375
1376### Example 7: Implementing a Custom Tab Switching Animation
1377
1378This example uses **customContentTransition** to implement a custom tab switching animation.
1379
1380```ts
1381// xxx.ets
1382interface itemType {
1383  text: string,
1384  backgroundColor: Color
1385}
1386
1387@Entry
1388@Component
1389struct TabsCustomAnimationExample {
1390  @State data: itemType[] = [
1391    {
1392      text: 'Red',
1393      backgroundColor: Color.Red
1394    },
1395    {
1396      text: 'Yellow',
1397      backgroundColor: Color.Yellow
1398    },
1399    {
1400      text: 'Blue',
1401      backgroundColor: Color.Blue
1402    }]
1403  @State opacityList: number[] = []
1404  @State scaleList: number[] = []
1405
1406  private durationList: number[] = []
1407  private timeoutList: number[] = []
1408  private customContentTransition: (from: number, to: number) => TabContentAnimatedTransition = (from: number, to: number) => {
1409    let tabContentAnimatedTransition = {
1410      timeout: this.timeoutList[from],
1411      transition: (proxy: TabContentTransitionProxy) => {
1412        this.scaleList[from] = 1.0
1413        this.scaleList[to] = 0.5
1414        this.opacityList[from] = 1.0
1415        this.opacityList[to] = 0.5
1416        animateTo({
1417          duration: this.durationList[from],
1418          onFinish: () => {
1419            proxy.finishTransition()
1420          }
1421        }, () => {
1422          this.scaleList[from] = 0.5
1423          this.scaleList[to] = 1.0
1424          this.opacityList[from] = 0.5
1425          this.opacityList[to] = 1.0
1426        })
1427      }
1428    } as TabContentAnimatedTransition
1429    return tabContentAnimatedTransition
1430  }
1431
1432  aboutToAppear(): void {
1433    let duration = 1000
1434    let timeout = 1000
1435    for (let i = 1; i <= this.data.length; i++) {
1436      this.opacityList.push(1.0)
1437      this.scaleList.push(1.0)
1438      this.durationList.push(duration * i)
1439      this.timeoutList.push(timeout * i)
1440    }
1441  }
1442
1443  build() {
1444    Column() {
1445      Tabs() {
1446        ForEach(this.data, (item: itemType, index: number) => {
1447          TabContent() {}
1448          .tabBar(item.text)
1449          .backgroundColor(item.backgroundColor)
1450          // Customize the opacity and scale animation.
1451          .opacity(this.opacityList[index])
1452          .scale({ x: this.scaleList[index], y: this.scaleList[index] })
1453        })
1454      }
1455      .backgroundColor(0xf1f3f5)
1456      .width('100%')
1457      .height(500)
1458      .customContentTransition(this.customContentTransition)
1459    }
1460  }
1461}
1462```
1463
1464![tabs5](figures/tabs8.gif)
1465
1466### Example 8: Intercepting Page Switching
1467
1468This example uses **onContentWillChange** to intercept and customize the gesture-based swiping actions for page switching.
1469
1470```ts
1471//xxx.ets
1472@Entry
1473@Component
1474struct TabsExample {
1475  @State selectedIndex: number = 2
1476  @State currentIndex: number = 2
1477  private controller: TabsController = new TabsController()
1478  @Builder tabBuilder(title: string,targetIndex: number) {
1479    Column(){
1480      Text(title).fontColor(this.selectedIndex === targetIndex ? '#1698CE' : '#6B6B6B')
1481    }.width('100%')
1482    .height(50)
1483    .justifyContent(FlexAlign.Center)
1484  }
1485  build() {
1486    Column() {
1487      Tabs({ barPosition: BarPosition.End, index: this.currentIndex, controller: this.controller }) {
1488        TabContent() {
1489          Column(){
1490            Text('Home tab content')
1491          }.width('100%').height('100%').backgroundColor('#00CB87').justifyContent(FlexAlign.Center)
1492        }.tabBar(this.tabBuilder('Home',0))
1493
1494        TabContent() {
1495          Column(){
1496            Text('Discover tab content')
1497          }.width('100%').height('100%').backgroundColor('#007DFF').justifyContent(FlexAlign.Center)
1498        }.tabBar(this.tabBuilder('Discover',1))
1499
1500        TabContent() {
1501          Column(){
1502            Text('Recommended tab content')
1503          }.width('100%').height('100%').backgroundColor('#FFBF00').justifyContent(FlexAlign.Center)
1504        }.tabBar(this.tabBuilder('Recommended',2))
1505
1506        TabContent() {
1507          Column(){
1508            Text('Me tab content')
1509          }.width('100%').height('100%').backgroundColor('#E67C92').justifyContent(FlexAlign.Center)
1510        }.tabBar(this.tabBuilder('Me',3))
1511      }
1512      .vertical(false)
1513      .barMode(BarMode.Fixed)
1514      .barWidth(360)
1515      .barHeight(60)
1516      .animationDuration(0)
1517      .onChange((index: number) => {
1518        this.currentIndex = index
1519        this.selectedIndex = index
1520      })
1521      .width(360)
1522      .height(600)
1523      .backgroundColor('#F1F3F5')
1524      .scrollable(true)
1525      .onContentWillChange((currentIndex, comingIndex) => {
1526        if (comingIndex == 2) {
1527          return false
1528        }
1529        return true
1530      })
1531
1532      Button('Change Index').width('50%').margin({ top: 20 })
1533        .onClick(()=>{
1534          this.currentIndex = (this.currentIndex + 1) % 4
1535        })
1536
1537      Button('changeIndex').width('50%').margin({ top: 20 })
1538        .onClick(()=>{
1539          this.currentIndex = (this.currentIndex + 1) % 4
1540          this.controller.changeIndex(this.currentIndex)
1541        })
1542    }.width('100%')
1543  }
1544}
1545```
1546
1547![tabs9](figures/tabs9.gif)
1548
1549### Example 9: Customizing the Tab Bar Switching Animation
1550
1551This example uses **onChange**, **onAnimationStart**, **onAnimationEnd**, and **onGestureSwipe** APIs to customize the tab bar switching animation.
1552
1553<!--code_no_check-->
1554
1555```ts
1556// EntryAbility.ets
1557import { Configuration, UIAbility } from '@kit.AbilityKit';
1558import { i18n } from '@kit.LocalizationKit';
1559import { CommonUtil } from '../common/CommonUtil';
1560
1561export default class EntryAbility extends UIAbility {
1562  onConfigurationUpdate(newConfig: Configuration): void {
1563    // Listen for system configuration changes.
1564    if (newConfig.language) {
1565      CommonUtil.setIsRTL(i18n.isRTL(newConfig.language))
1566    }
1567  }
1568}
1569```
1570
1571<!--code_no_check-->
1572
1573```ts
1574// CommonUtil.ets
1575import { i18n, intl } from '@kit.LocalizationKit';
1576
1577export class CommonUtil {
1578  private static isRTL: boolean = i18n.isRTL((new intl.Locale()).language)
1579
1580  public static setIsRTL(isRTL: boolean): void {
1581    CommonUtil.isRTL = isRTL
1582  }
1583
1584  public static getIsRTL(): boolean {
1585    return CommonUtil.isRTL
1586  }
1587}
1588```
1589
1590<!--code_no_check-->
1591
1592```ts
1593// xxx.ets
1594import { LengthMetrics } from '@kit.ArkUI';
1595import { CommonUtil } from '../common/CommonUtil';
1596
1597@Entry
1598@Component
1599struct TabsExample {
1600  @State colorArray: [string, string][] =
1601    [['green', '#00CB87'], ['blue', '#007DFF'], ['yellow', '#FFBF00'], ['pink', '#E67C92']]
1602  @State currentIndex: number = 0
1603  @State animationDuration: number = 300
1604  @State indicatorLeftMargin: number = 0
1605  @State indicatorWidth: number = 0
1606  private tabsWidth: number = 0
1607  private textInfos: [number, number][] = []
1608  private isStartAnimateTo: boolean = false
1609
1610  aboutToAppear():void {
1611    for (let i = 0; i < this.colorArray.length; i++) {
1612      this.textInfos.push([0, 0]);
1613    }
1614  }
1615
1616  @Builder
1617  tabBuilder(index: number, name: string) {
1618    Column() {
1619      Text(name)
1620        .fontSize(16)
1621        .fontColor(this.currentIndex === index ? '#007DFF' : '#182431')
1622        .fontWeight(this.currentIndex === index ? 500 : 400)
1623        .id(index.toString())
1624        .onAreaChange((oldValue: Area, newValue: Area) => {
1625          this.textInfos[index] = [newValue.globalPosition.x as number, newValue.width as number]
1626          if (!this.isStartAnimateTo && this.currentIndex === index && this.tabsWidth > 0) {
1627            this.setIndicatorAttr(this.textInfos[this.currentIndex][0], this.textInfos[this.currentIndex][1])
1628          }
1629        })
1630    }.width('100%')
1631  }
1632
1633  build() {
1634    Stack({ alignContent: Alignment.TopStart }) {
1635      Tabs({ barPosition: BarPosition.Start }) {
1636        ForEach(this.colorArray, (item: [string, string], index:number) => {
1637          TabContent() {
1638            Column().width('100%').height('100%').backgroundColor(item[1])
1639          }.tabBar(this.tabBuilder(index, item[0]))
1640        })
1641      }
1642      .onAreaChange((oldValue: Area, newValue: Area)=> {
1643        this.tabsWidth = newValue.width as number
1644        if (!this.isStartAnimateTo) {
1645          this.setIndicatorAttr(this.textInfos[this.currentIndex][0], this.textInfos[this.currentIndex][1])
1646        }
1647      })
1648      .barWidth('100%')
1649      .barHeight(56)
1650      .width('100%')
1651      .height(296)
1652      .backgroundColor('#F1F3F5')
1653      .animationDuration(this.animationDuration)
1654      .onChange((index: number) => {
1655        this.currentIndex = index // Listen for index changes to switch between tab pages.
1656      })
1657      .onAnimationStart((index: number, targetIndex: number, event: TabsAnimationEvent) => {
1658        // Triggered when the tab switching animation starts. The underline moves with the active tab, along with a width gradient.
1659        this.currentIndex = targetIndex
1660        this.startAnimateTo(this.animationDuration, this.textInfos[targetIndex][0], this.textInfos[targetIndex][1])
1661      })
1662      .onAnimationEnd((index: number, event: TabsAnimationEvent) => {
1663        // Triggered when the tab switching animation ends. The underline animation stops.
1664        let currentIndicatorInfo = this.getCurrentIndicatorInfo(index, event)
1665        this.startAnimateTo(0, currentIndicatorInfo.left, currentIndicatorInfo.width)
1666      })
1667      .onGestureSwipe((index: number, event: TabsAnimationEvent) => {
1668        // Triggered on a frame-by-frame basis when the tab is switched by a swipe.
1669        let currentIndicatorInfo = this.getCurrentIndicatorInfo(index, event)
1670        this.currentIndex = currentIndicatorInfo.index
1671        this.setIndicatorAttr(currentIndicatorInfo.left, currentIndicatorInfo.width)
1672      })
1673
1674      Column()
1675        .height(2)
1676        .width(this.indicatorWidth)
1677        .margin({ start: LengthMetrics.vp(this.indicatorLeftMargin), top: LengthMetrics.vp(48) })
1678        .backgroundColor('#007DFF')
1679    }.width('100%')
1680  }
1681
1682  private getCurrentIndicatorInfo(index: number, event: TabsAnimationEvent): Record<string, number> {
1683    let nextIndex = index
1684    if (index > 0 && (CommonUtil.getIsRTL() ? event.currentOffset < 0 : event.currentOffset > 0)) {
1685      nextIndex--
1686    } else if (index < this.textInfos.length - 1 &&
1687        (CommonUtil.getIsRTL() ? event.currentOffset > 0 : event.currentOffset < 0)) {
1688      nextIndex++
1689    }
1690    let indexInfo = this.textInfos[index]
1691    let nextIndexInfo = this.textInfos[nextIndex]
1692    let swipeRatio = Math.abs(event.currentOffset / this.tabsWidth)
1693    let currentIndex = swipeRatio > 0.5 ? nextIndex : index // If the swipe distance exceeds half the page width, the tab bar switches to the next page.
1694    let currentLeft = indexInfo[0] + (nextIndexInfo[0] - indexInfo[0]) * swipeRatio
1695    let currentWidth = indexInfo[1] + (nextIndexInfo[1] - indexInfo[1]) * swipeRatio
1696    return { 'index': currentIndex, 'left': currentLeft, 'width': currentWidth }
1697  }
1698
1699  private startAnimateTo(duration: number, leftMargin: number, width: number) {
1700    this.isStartAnimateTo = true
1701    animateTo({
1702      duration: duration, // Animation duration.
1703      curve: Curve.Linear, // Animation curve.
1704      iterations: 1, // Number of playback times.
1705      playMode: PlayMode.Normal, // Animation playback mode.
1706      onFinish: () => {
1707        this.isStartAnimateTo = false
1708        console.info('play end')
1709      }
1710    }, () => {
1711      this.setIndicatorAttr(leftMargin, width)
1712    })
1713  }
1714
1715  private setIndicatorAttr(leftMargin: number, width: number) {
1716    this.indicatorWidth = width
1717    if (CommonUtil.getIsRTL()) {
1718      this.indicatorLeftMargin = this.tabsWidth - leftMargin - width
1719    } else {
1720      this.indicatorLeftMargin = leftMargin
1721    }
1722  }
1723}
1724```
1725
1726![tabs10](figures/tabs10.gif)
1727
1728### Example 10: Preloading Child Nodes
1729
1730In this example, the **preloadItems** API is used to preload specified child nodes.
1731
1732```ts
1733// xxx.ets
1734import { BusinessError } from '@kit.BasicServicesKit';
1735
1736@Entry
1737@Component
1738struct TabsPreloadItems {
1739  @State currentIndex: number = 1
1740  private tabsController: TabsController = new TabsController()
1741
1742  build() {
1743    Column() {
1744      Tabs({ index: this.currentIndex, controller: this.tabsController }) {
1745        TabContent() {
1746          MyComponent({ color: '#00CB87' })
1747        }.tabBar(SubTabBarStyle.of('green'))
1748
1749        TabContent() {
1750          MyComponent({ color: '#007DFF' })
1751        }.tabBar(SubTabBarStyle.of('blue'))
1752
1753        TabContent() {
1754          MyComponent({ color: '#FFBF00' })
1755        }.tabBar(SubTabBarStyle.of('yellow'))
1756
1757        TabContent() {
1758          MyComponent({ color: '#E67C92' })
1759        }.tabBar(SubTabBarStyle.of('pink'))
1760      }
1761      .width(360)
1762      .height(296)
1763      .backgroundColor('#F1F3F5')
1764      .onChange((index: number) => {
1765        this.currentIndex = index
1766      })
1767
1768      Button('preload items: [0, 2, 3]')
1769        .margin(5)
1770        .onClick(() => {
1771          // Preload child nodes 0, 2, and 3 to improve the performance when users swipe or click to switch to these nodes.
1772          this.tabsController.preloadItems([0, 2, 3])
1773            .then(() => {
1774              console.info('preloadItems success.')
1775            })
1776            .catch((error: BusinessError) => {
1777              console.error('preloadItems failed, error code: ' + error.code + ', error message: ' + error.message)
1778            })
1779        })
1780    }
1781  }
1782}
1783
1784@Component
1785struct MyComponent {
1786  private color: string = ""
1787
1788  aboutToAppear(): void {
1789    console.info('aboutToAppear backgroundColor:' + this.color)
1790  }
1791
1792  aboutToDisappear(): void {
1793    console.info('aboutToDisappear backgroundColor:' + this.color)
1794  }
1795
1796  build() {
1797    Column()
1798      .width('100%')
1799      .height('100%')
1800      .backgroundColor(this.color)
1801  }
1802}
1803```
1804
1805### Example 11: Setting Tab Bar Translation and Opacity
1806
1807This example demonstrates how to set the translation distance and opacity of the tab bar using the **setTabBarTranslate** and **setTabBarOpacity** APIs.
1808
1809```ts
1810// xxx.ets
1811@Entry
1812@Component
1813struct TabsExample {
1814  private controller: TabsController = new TabsController()
1815
1816  build() {
1817    Column() {
1818      Button('Set TabBar Translation Distance').margin({ top: 20 })
1819        .onClick(() => {
1820          this.controller.setTabBarTranslate({ x: -20, y: -20 })
1821        })
1822
1823      Button('Set TabBar Opacity').margin({ top: 20 })
1824        .onClick(() => {
1825          this.controller.setTabBarOpacity(0.5)
1826        })
1827
1828      Tabs({ barPosition: BarPosition.End, controller: this.controller }) {
1829        TabContent() {
1830          Column().width('100%').height('100%').backgroundColor('#00CB87')
1831        }.tabBar(BottomTabBarStyle.of($r('app.media.startIcon'), 'green'))
1832
1833        TabContent() {
1834          Column().width('100%').height('100%').backgroundColor('#007DFF')
1835        }.tabBar(BottomTabBarStyle.of($r('app.media.startIcon'), 'blue'))
1836
1837        TabContent() {
1838          Column().width('100%').height('100%').backgroundColor('#FFBF00')
1839        }.tabBar(BottomTabBarStyle.of($r('app.media.startIcon'), 'yellow'))
1840
1841        TabContent() {
1842          Column().width('100%').height('100%').backgroundColor('#E67C92')
1843        }.tabBar(BottomTabBarStyle.of($r('app.media.startIcon'), 'pink'))
1844      }
1845      .width(360)
1846      .height(296)
1847      .margin({ top: 20 })
1848      .barBackgroundColor('#F1F3F5')
1849    }
1850    .width('100%')
1851  }
1852}
1853```
1854
1855![tabs11](figures/tabs11.gif)
1856
1857### Example 12: Implementing Lazy Loading and Resource Release of Pages
1858
1859This example demonstrates how to use a custom tab bar with the **Swiper** component and **LazyForEach** to implement lazy loading and resource release of pages.
1860
1861```ts
1862// xxx.ets
1863class MyDataSource implements IDataSource {
1864  private list: number[] = []
1865
1866  constructor(list: number[]) {
1867    this.list = list
1868  }
1869
1870  totalCount(): number {
1871    return this.list.length
1872  }
1873
1874  getData(index: number): number {
1875    return this.list[index]
1876  }
1877
1878  registerDataChangeListener(listener: DataChangeListener): void {
1879  }
1880
1881  unregisterDataChangeListener() {
1882  }
1883}
1884
1885@Entry
1886@Component
1887struct TabsSwiperExample {
1888  @State fontColor: string = '#182431'
1889  @State selectedFontColor: string = '#007DFF'
1890  @State currentIndex: number = 0
1891  private list: number[] = []
1892  private tabsController: TabsController = new TabsController()
1893  private swiperController: SwiperController = new SwiperController()
1894  private swiperData: MyDataSource = new MyDataSource([])
1895
1896  aboutToAppear(): void {
1897    for (let i = 0; i <= 9; i++) {
1898      this.list.push(i);
1899    }
1900    this.swiperData = new MyDataSource(this.list)
1901  }
1902
1903  @Builder tabBuilder(index: number, name: string) {
1904    Column() {
1905      Text(name)
1906        .fontColor(this.currentIndex === index ? this.selectedFontColor : this.fontColor)
1907        .fontSize(16)
1908        .fontWeight(this.currentIndex === index ? 500 : 400)
1909        .lineHeight(22)
1910        .margin({ top: 17, bottom: 7 })
1911      Divider()
1912        .strokeWidth(2)
1913        .color('#007DFF')
1914        .opacity(this.currentIndex === index ? 1 : 0)
1915    }.width('20%')
1916  }
1917
1918  build() {
1919    Column() {
1920      Tabs({ barPosition: BarPosition.Start, controller: this.tabsController }) {
1921        ForEach(this.list, (item: number) => {
1922          TabContent().tabBar(this.tabBuilder(item, 'Tab ' + this.list[item]))
1923        })
1924      }
1925      .onTabBarClick((index: number) => {
1926        this.currentIndex = index
1927        this.swiperController.changeIndex(index, true)
1928      })
1929      .barMode(BarMode.Scrollable)
1930      .backgroundColor('#F1F3F5')
1931      .height(56)
1932      .width('100%')
1933
1934      Swiper(this.swiperController) {
1935        LazyForEach(this.swiperData, (item: string) => {
1936          Text(item.toString())
1937            .onAppear(()=>{
1938              console.info('onAppear ' + item.toString())
1939            })
1940            .onDisAppear(()=>{
1941              console.info('onDisAppear ' + item.toString())
1942            })
1943            .width('100%')
1944            .height('100%')
1945            .backgroundColor(0xAFEEEE)
1946            .textAlign(TextAlign.Center)
1947            .fontSize(30)
1948        }, (item: string) => item)
1949      }
1950      .loop(false)
1951      .onChange((index: number) => {
1952        this.currentIndex = index
1953      })
1954      .onAnimationStart((index: number, targetIndex: number, extraInfo: SwiperAnimationEvent) => {
1955        this.currentIndex = targetIndex
1956        this.tabsController.changeIndex(targetIndex)
1957      })
1958    }
1959  }
1960}
1961```
1962
1963![tabs12](figures/tabs12.gif)
1964
1965### Example 13: Enabling Tabs to Exceed the Tab Bar Area
1966
1967This example shows how to enable tabs to exceed the tab bar area by setting the **clip** property of the **TabBar** using **barModifier**.
1968
1969```ts
1970// xxx.ets
1971import { CommonModifier } from '@kit.ArkUI';
1972
1973@Entry
1974@Component
1975struct TabsBarModifierExample {
1976  @State selectedIndex: number = 2
1977  @State currentIndex: number = 2
1978  @State isClip: boolean = false
1979  @State tabBarModifier: CommonModifier = new CommonModifier()
1980  private controller: TabsController = new TabsController()
1981
1982  aboutToAppear(): void {
1983    this.tabBarModifier.clip(this.isClip)
1984  }
1985
1986  @Builder
1987  tabBuilder(title: string, targetIndex: number) {
1988    Column() {
1989      Image($r("app.media.startIcon")).width(30).height(30)
1990      Text(title).fontColor(this.selectedIndex === targetIndex ? '#1698CE' : '#6B6B6B')
1991    }.width('100%')
1992    .height(50)
1993    .justifyContent(FlexAlign.Center)
1994    .offset({ y: this.selectedIndex === targetIndex ? -15 : 0 })
1995  }
1996
1997  build() {
1998    Column() {
1999      Tabs({
2000        barPosition: BarPosition.End,
2001        index: this.currentIndex,
2002        controller: this.controller,
2003        barModifier: this.tabBarModifier
2004      }) {
2005        TabContent() {
2006          Column() {
2007            Text('Home tab content')
2008          }.width('100%').height('100%').backgroundColor('#00CB87').justifyContent(FlexAlign.Center)
2009        }.tabBar(this.tabBuilder('Home', 0))
2010
2011        TabContent() {
2012          Column() {
2013            Text('Discover tab content')
2014          }.width('100%').height('100%').backgroundColor('#007DFF').justifyContent(FlexAlign.Center)
2015        }.tabBar(this.tabBuilder('Discover', 1))
2016
2017        TabContent() {
2018          Column() {
2019            Text('Recommended tab content')
2020          }.width('100%').height('100%').backgroundColor('#FFBF00').justifyContent(FlexAlign.Center)
2021        }.tabBar(this.tabBuilder('Recommended', 2))
2022
2023        TabContent() {
2024          Column() {
2025            Text('Me tab content')
2026          }.width('100%').height('100%').backgroundColor('#E67C92').justifyContent(FlexAlign.Center)
2027        }.tabBar(this.tabBuilder('Me',3))
2028      }
2029      .vertical(false)
2030      .barMode(BarMode.Fixed)
2031      .barWidth(340)
2032      .barHeight(60)
2033      .onChange((index: number) => {
2034        this.currentIndex = index
2035        this.selectedIndex = index
2036      })
2037      .width(340)
2038      .height(400)
2039      .backgroundColor('#F1F3F5')
2040      .scrollable(true)
2041
2042      Button("isClip: " + this.isClip)
2043        .margin({ top: 30 })
2044        .onClick(() => {
2045          this.isClip = !this.isClip
2046          this.tabBarModifier.clip(this.isClip)
2047        })
2048    }.width('100%')
2049  }
2050}
2051```
2052
2053
2054
2055### Example 14: Aligning Tabs
2056
2057This example demonstrates how to align tabs by setting the **align** property of the **TabBar** using **barModifier**.
2058
2059```ts
2060// xxx.ets
2061import { CommonModifier } from '@kit.ArkUI';
2062
2063@Entry
2064@Component
2065struct TabsBarModifierExample {
2066  private controller: TabsController = new TabsController()
2067  @State text: string = "Text"
2068  @State isVertical: boolean = false
2069  @State tabBarModifier: CommonModifier = new CommonModifier()
2070
2071  build() {
2072    Column() {
2073      Row() {
2074        Button("Alignment.Start ")
2075          .width('47%')
2076          .height(50)
2077          .margin({ top: 5 })
2078          .onClick((event?: ClickEvent) => {
2079            this.tabBarModifier.align(Alignment.Start)
2080          })
2081          .margin({ right: '6%', bottom: '12vp' })
2082        Button("Alignment.End")
2083          .width('47%')
2084          .height(50)
2085          .margin({ top: 5 })
2086          .onClick((event?: ClickEvent) => {
2087            this.tabBarModifier.align(Alignment.End)
2088          })
2089          .margin({ bottom: '12vp' })
2090      }
2091
2092      Row() {
2093        Button("Alignment.Center")
2094          .width('47%')
2095          .height(50)
2096          .margin({ top: 5 })
2097          .onClick((event?: ClickEvent) => {
2098            this.tabBarModifier.align(Alignment.Center)
2099          })
2100          .margin({ right: '6%', bottom: '12vp' })
2101        Button("isVertical: " + this.isVertical)
2102          .width('47%')
2103          .height(50)
2104          .margin({ top: 5 })
2105          .onClick((event?: ClickEvent) => {
2106            this.isVertical = !this.isVertical
2107          })
2108          .margin({ bottom: '12vp' })
2109      }
2110
2111      Row() {
2112        Button("Alignment.Top")
2113          .width('47%')
2114          .height(50)
2115          .margin({ top: 5 })
2116          .onClick((event?: ClickEvent) => {
2117            this.tabBarModifier.align(Alignment.Top)
2118          })
2119          .margin({ right: '6%', bottom: '12vp' })
2120        Button("Alignment.Bottom")
2121          .width('47%')
2122          .height(50)
2123          .margin({ top: 5 })
2124          .onClick((event?: ClickEvent) => {
2125            this.tabBarModifier.align(Alignment.Bottom)
2126          })
2127          .margin({ bottom: '12vp' })
2128      }
2129
2130      Tabs({ barPosition: BarPosition.End, controller: this.controller, barModifier: this.tabBarModifier }) {
2131        TabContent() {
2132          Column().width('100%').height('100%').backgroundColor(Color.Pink)
2133        }.tabBar(SubTabBarStyle.of(this.text))
2134
2135        TabContent() {
2136          Column().width('100%').height('100%').backgroundColor(Color.Green)
2137        }.tabBar(SubTabBarStyle.of(this.text))
2138
2139        TabContent() {
2140          Column().width('100%').height('100%').backgroundColor(Color.Blue)
2141        }.tabBar(SubTabBarStyle.of(this.text))
2142      }
2143      .vertical(this.isVertical)
2144      .height('60%')
2145      .backgroundColor(0xf1f3f5)
2146      .barMode(BarMode.Scrollable)
2147    }
2148    .width('100%')
2149    .height(500)
2150    .margin({ top: 5 })
2151    .padding('24vp')
2152  }
2153}
2154```
2155
2156
2157
2158### Example 15: Setting the Tab Switching Animation
2159
2160This example demonstrates how to implement a tab switching animation by setting **animationMode**.
2161
2162```ts
2163// xxx.ets
2164class TabsMyDataSource implements IDataSource {
2165  private list: number[] = []
2166  constructor(list: number[]) {
2167    this.list = list
2168  }
2169  totalCount(): number {
2170    return this.list.length
2171  }
2172  getData(index: number): number {
2173    return this.list[index]
2174  }
2175  registerDataChangeListener(listener: DataChangeListener): void {
2176  }
2177  unregisterDataChangeListener() {
2178  }
2179}
2180@Entry
2181@Component
2182struct TabsExample {
2183  @State currentIndex: number = 0
2184  @State currentAnimationMode: AnimationMode = AnimationMode.CONTENT_FIRST
2185  private controller: TabsController = new TabsController()
2186  private data: TabsMyDataSource = new TabsMyDataSource([])
2187  private sum : number = 10
2188  aboutToAppear(): void {
2189    let list: number[] = []
2190    for (let i = 0; i < this.sum; i++) {
2191      list.push(i);
2192    }
2193    this.data = new TabsMyDataSource(list)
2194  }
2195  @Builder
2196  tabBuilder(title: string,targetIndex: number) {
2197    Column(){
2198      Text(title).fontColor(this.currentIndex === targetIndex ? '#FF0000' : '#6B6B6B')
2199    }.width('100%')
2200    .height(50)
2201    .justifyContent(FlexAlign.Center)
2202  }
2203  build() {
2204    Column() {
2205      Tabs({ barPosition: BarPosition.End, controller: this.controller, index: this.currentIndex }) {
2206        LazyForEach(this.data, (item: string) => {
2207          TabContent() {
2208            Column(){
2209              Text('' + item)
2210            }.width('100%').height('100%').backgroundColor('#00CB87').justifyContent(FlexAlign.Center)
2211          }.tabBar(this.tabBuilder('P' + item, parseInt(item)))
2212        }, (item: string) => item)
2213      }
2214      .vertical(false)
2215      .barMode(BarMode.Fixed)
2216      .barWidth(360)
2217      .barHeight(60)
2218      .animationMode(this.currentAnimationMode)
2219      .animationDuration(4000)
2220      .onChange((index: number) => {
2221        this.currentIndex = index
2222      })
2223      .width(360)
2224      .height(120)
2225      .backgroundColor('#F1F3F5')
2226      .scrollable(true)
2227      Text('AnimationMode:' + AnimationMode[this.currentAnimationMode])
2228      Button('AnimationMode').width('50%').margin({ top: 1 }).height(25)
2229        .onClick(()=>{
2230          if (this.currentAnimationMode === AnimationMode.CONTENT_FIRST) {
2231            this.currentAnimationMode = AnimationMode.ACTION_FIRST
2232          } else if (this.currentAnimationMode === AnimationMode.ACTION_FIRST) {
2233            this.currentAnimationMode = AnimationMode.NO_ANIMATION
2234          } else if (this.currentAnimationMode === AnimationMode.NO_ANIMATION) {
2235            this.currentAnimationMode = AnimationMode.CONTENT_FIRST_WITH_JUMP
2236          } else if (this.currentAnimationMode === AnimationMode.CONTENT_FIRST_WITH_JUMP) {
2237            this.currentAnimationMode = AnimationMode.ACTION_FIRST_WITH_JUMP
2238          } else if (this.currentAnimationMode === AnimationMode.ACTION_FIRST_WITH_JUMP) {
2239            this.currentAnimationMode = AnimationMode.CONTENT_FIRST
2240          }
2241        })
2242    }.width('100%')
2243  }
2244}
2245```
2246
2247![tabs15](figures/tabs15.gif)
2248
2249