• 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](../../../ui/state-management/arkts-rendering-control-ifelse.md) and [ForEach](../../../ui/state-management/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 13](#example-13-implementing-lazy-loading-and-resource-release-of-pages).
21
22
23## APIs
24
25Tabs(options?: TabsOptions)
26
27Create a **Tabs** container.
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**System capability**: SystemCapability.ArkUI.ArkUI.Full
44
45| Name        | Type                             | Mandatory  | Description                                    |
46| ----------- | --------------------------------- | ---- | ---------------------------------------- |
47| barPosition<sup>7+</sup> | [BarPosition](#barposition)| No   | Position of the **Tabs** component.<br>Default value: **BarPosition.Start**<br>**Atomic service API**: This API can be used in atomic services since API version 11.  |
48| index<sup>7+</sup>       | 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 [$$](../../../ui/state-management/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.<br>**Atomic service API**: This API can be used in atomic services since API version 11.|
49| controller<sup>7+</sup>  | [TabsController](#tabscontroller) | No   | Tab controller.<br>**Atomic service API**: This API can be used in atomic services since API version 11.        |
50| 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), [barBackgroundBlurStyle](#barbackgroundblurstyle18), and [barBackgroundEffect](#barbackgroundeffect18) 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#backgroundcolor18), [backgroundBlurStyle](ts-universal-attributes-background.md#backgroundblurstyle18), and [backgroundEffect](ts-universal-attributes-background.md#backgroundeffect18) 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#tabbar18) attribute of the [TabContent](ts-container-tabcontent.md) component does not support the dragging feature.<br>**Atomic service API**: This API can be used in atomic services since API version 15.|
51
52## BarPosition
53
54Enumerates the positions of the **Tabs** component.
55
56**Atomic service API**: This API can be used in atomic services since API version 11.
57
58**System capability**: SystemCapability.ArkUI.ArkUI.Full
59
60| Name | Description                                                        |
61| ----- | ------------------------------------------------------------ |
62| 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.|
63| 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.|
64
65
66## Attributes
67
68In addition to the [universal attributes](ts-component-general-attributes.md), the following attributes are supported.
69
70### vertical
71
72vertical(value: boolean)
73
74Sets whether to use vertical tabs.
75
76**Atomic service API**: This API can be used in atomic services since API version 11.
77
78**System capability**: SystemCapability.ArkUI.ArkUI.Full
79
80**Parameters**
81
82| Name| Type   | Mandatory| Description                                                        |
83| ------ | ------- | ---- | ------------------------------------------------------------ |
84| 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.|
85
86### scrollable
87
88scrollable(value: boolean)
89
90Sets whether the tabs are scrollable.
91
92**Atomic service API**: This API can be used in atomic services since API version 11.
93
94**System capability**: SystemCapability.ArkUI.ArkUI.Full
95
96**Parameters**
97
98| Name| Type   | Mandatory| Description                                                        |
99| ------ | ------- | ---- | ------------------------------------------------------------ |
100| value  | boolean | Yes  | Whether the tabs are scrollable.<br>**true** (default): The tabs are scrollable.<br> **false**: The tabs are not scrollable.|
101
102### barMode
103
104barMode(value: BarMode, options?: ScrollableBarModeOptions)
105
106Sets the tab bar layout mode.
107
108**Atomic service API**: This API can be used in atomic services since API version 11.
109
110**System capability**: SystemCapability.ArkUI.ArkUI.Full
111
112**Parameters**
113
114| Name               | Type                                                        | Mandatory| Description                                                        |
115| --------------------- | ------------------------------------------------------------ | ---- | ------------------------------------------------------------ |
116| value                 | [BarMode](#barmode)                                  | Yes  | Layout mode.<br>Default value: **BarMode.Fixed**                                                |
117| 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.|
118
119### barMode<sup>10+</sup>
120
121barMode(value: BarMode.Fixed)
122
123Sets the tab bar layout mode to **BarMode.Fixed**.
124
125**Atomic service API**: This API can be used in atomic services since API version 11.
126
127**System capability**: SystemCapability.ArkUI.ArkUI.Full
128
129**Parameters**
130
131| Name   | Type                            | Mandatory| Description                                   |
132| -------- | -------------------------------- | ---- | ------------------------------------ |
133| 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).  |
134
135### barMode<sup>10+</sup>
136
137barMode(value: BarMode.Scrollable, options: ScrollableBarModeOptions)
138
139Sets the tab bar layout mode to **BarMode.Scrollable**.
140
141**Atomic service API**: This API can be used in atomic services since API version 11.
142
143**System capability**: SystemCapability.ArkUI.ArkUI.Full
144
145**Parameters**
146
147| Name   | Type                             | Mandatory| Description                                   |
148| -------- | --------------------------------- | ---- | ------------------------------------- |
149| 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.       |
150| 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. |
151
152### barWidth
153
154barWidth(value: Length)
155
156Sets 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.
157
158**Atomic service API**: This API can be used in atomic services since API version 11.
159
160**System capability**: SystemCapability.ArkUI.ArkUI.Full
161
162**Parameters**
163
164| Name| Type                                     | Mandatory| Description                                                        |
165| ------ | ----------------------------------------- | ---- | ------------------------------------------------------------ |
166| 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.|
167
168### barHeight
169
170barHeight(value: Length)
171
172Sets the height of the tab bar. For horizontal **Tabs** components, you can set the height to **'auto'** to allow the tab bar to automatically adapt to the height of its child components. If the height is set to a value less than 0 or greater than the height of the **Tabs** component, the default value is used.
173
174In versions earlier than API version 14, setting **barHeight** to a fixed value prevents 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.
175
176**Atomic service API**: This API can be used in atomic services since API version 11.
177
178**System capability**: SystemCapability.ArkUI.ArkUI.Full
179
180**Parameters**
181
182| Name| Type                                     | Mandatory| Description                                                        |
183| ------ | ----------------------------------------- | ---- | ------------------------------------------------------------ |
184| 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.|
185
186### barHeight<sup>20+</sup>
187
188barHeight(height: Length, noMinHeightLimit: boolean)
189
190Sets the height of the tab bar. For horizontal **Tabs** components, you can set the height to **'auto'** to allow the tab bar to automatically adapt to the height of its child components; you can also set **noMinHeightLimit** to **true** so that the adaptive height can be less than the default tab bar height. If the height is set to a value less than 0 or greater than the height of the **Tabs** component, the default value is used.
191
192**Atomic service API**: This API can be used in atomic services since API version 20.
193
194**System capability**: SystemCapability.ArkUI.ArkUI.Full
195
196**Parameters**
197
198| Name          | Type                        | Mandatory| Description                                                        |
199| ---------------- | ---------------------------- | ---- | ------------------------------------------------------------ |
200| height           | [Length](ts-types.md#length) | 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 48 vp.|
201| noMinHeightLimit | boolean                      | Yes  | Whether to remove the minimum height limit of the tab bar when **height** is set to **'auto'**. The default value is **false**.<br>**NOTE**<br>**true**: removes the minimum height limit, allowing the height to be less than the default value.<br>**false**: enforces the minimum height limit, meaning the height cannot be less than the default value.|
202
203### animationCurve<sup>20+</sup>
204
205animationCurve(curve: Curve | ICurve)
206
207Sets the tab switching animation curve for the **Tabs** component. For details about commonly used curves, refer to the [Curve](ts-appendix-enums.md#curve) enum. Custom interpolation curve objects can also be created using the APIs provided in the [interpolation calculation](../js-apis-curve.md) module.
208
209**Atomic service API**: This API can be used in atomic services since API version 20.
210
211**System capability**: SystemCapability.ArkUI.ArkUI.Full
212
213**Parameters**
214
215| Name| Type                                                        | Mandatory| Description                                       |
216| ------ | ------------------------------------------------------------ | ---- | ------------------------------------------- |
217| curve  | [Curve](ts-appendix-enums.md#curve) \| [ICurve](../js-apis-curve.md#icurve9) | Yes  | Tab switching animation curve.<br>Default value:<br>When pages are turned by swiping in **TabContent**, the default value is **interpolatingSpring(-1, 1, 228, 30)**.<br>When pages are turned by tapping tabs or calling the **changeIndex** API of **TabsController**, the default value is **cubicBezierCurve(0.2, 0.0, 0.1, 1.0)**.<br>When a custom animation curve is set, it applies to all tab switching animations—whether triggered by swiping, tapping a tab, or calling the **changeIndex** API.|
218
219### animationDuration
220
221animationDuration(value: number)
222
223Sets the duration of the tab switching animation for the **Tabs** component.
224
225If **animationCurve** is not set, **animationDuration** only controls the duration of tab switching animations triggered by tapping a tab or calling the **changeIndex** API, and page-turning animations triggered by swiping in **TabContent**, the duration is determined by the intrinsic parameters of the default curve **interpolatingSpring(-1, 1, 228, 30)**.
226
227For details about curves unaffected by **animationDuration**, see [Interpolation Calculation](../js-apis-curve.md). These curves include curves of type [springMotion](../js-apis-curve.md#curvesspringmotion9), [responsiveSpringMotion](../js-apis-curve.md#curvesresponsivespringmotion9), and [interpolatingSpring](../js-apis-curve.md#curvesinterpolatingspring10).
228
229**Atomic service API**: This API can be used in atomic services since API version 11.
230
231**System capability**: SystemCapability.ArkUI.ArkUI.Full
232
233**Parameters**
234
235| Name| Type  | Mandatory| Description                                                        |
236| ------ | ------ | ---- | ------------------------------------------------------------ |
237| value  | number | Yes  | Duration of the tab switching animation.<br>Default value:<br>API version 10 and earlier versions: If this parameter is set to **null** or is not set, the default value **0**, which means no animation for tab switching. If this parameter is set to **undefined** or a value less than 0, the default value is **300**.<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.<br>Value range: [0, +∞).|
238
239### animationMode<sup>12+</sup>
240
241animationMode(mode: Optional\<AnimationMode\>)
242
243Sets the animation mode for tab switching initiated by clicking a specific tab or by calling the **changeIndex** API of **TabsController**.
244
245**Atomic service API**: This API can be used in atomic services since API version 12.
246
247**System capability**: SystemCapability.ArkUI.ArkUI.Full
248
249**Parameters**
250
251| Name| Type  | Mandatory| Description                                                        |
252| ------ | ------ | ---- | ------------------------------------------------------------ |
253| 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.|
254
255### barPosition<sup>9+</sup>
256
257barPosition(value: BarPosition)
258
259Sets the position of the **Tabs** component.
260
261**Atomic service API**: This API can be used in atomic services since API version 11.
262
263**System capability**: SystemCapability.ArkUI.ArkUI.Full
264
265**Parameters**
266
267| Name| Type                              | Mandatory| Description                 |
268| ----- | ---------------------------------- | ---- | -------------------- |
269| value | [BarPosition](#barposition)| Yes | Position of the **Tabs** component.<br>Default value: **BarPosition.Start**  |
270
271### divider<sup>10+</sup>
272
273divider(value: DividerStyle | null)
274
275Sets the divider between the **TabBar** and **TabContent** components.
276
277**Atomic service API**: This API can be used in atomic services since API version 11.
278
279**System capability**: SystemCapability.ArkUI.ArkUI.Full
280
281**Parameters**
282
283| Name| Type                                                     | Mandatory| Description                                                        |
284| ------ | --------------------------------------------------------- | ---- | ------------------------------------------------------------ |
285| value  | [DividerStyle](#dividerstyle10) \| null | Yes  | Divider style. By default, the divider is not displayed.<br>**DividerStyle**: divider style.<br>**null**: No divider is displayed.|
286
287### fadingEdge<sup>10+</sup>
288
289fadingEdge(value: boolean)
290
291Sets whether the tabs fade out when they exceed the container width. It is recommended that this attribute be used together with the **barBackgroundColor** attribute. If **barBackgroundColor** is not defined, the default fade effect shows a white gradient at the container's edge.
292
293**Atomic service API**: This API can be used in atomic services since API version 11.
294
295**System capability**: SystemCapability.ArkUI.ArkUI.Full
296
297**Parameters**
298
299| Name| Type   | Mandatory| Description                                              |
300| ------ | ------- | ---- | -------------------------------------------------- |
301| value  | boolean | Yes  | Whether the tabs fade out when they exceed the container width.<br>**true** (default): The tab fades out when they exceed the container width.<br> **false**: The tabs are clipped without any fade effect when they exceed the container width.|
302
303### barOverlap<sup>10+</sup>
304
305barOverlap(value: boolean)
306
307Sets whether the tab bar overlaps the **TabContent** component with a blurred background effect.
308
309**Atomic service API**: This API can be used in atomic services since API version 11.
310
311**System capability**: SystemCapability.ArkUI.ArkUI.Full
312
313**Parameters**
314
315| Name| Type   | Mandatory| Description                                                        |
316| ------ | ------- | ---- | ------------------------------------------------------------ |
317| value  | boolean | Yes  | Whether the tab bar overlaps the **TabContent** component with a blurred background effect.<br> **true**: The tab bar overlaps the **TabContent** component with a blurred background effect, and the default blur style of the tab bar is set to **'BlurStyle.COMPONENT_THICK'**.<br> **false**: There is no blur or overlap effect.<br>Default value: **false**.|
318
319### barBackgroundColor<sup>10+</sup>
320
321barBackgroundColor(value: ResourceColor)
322
323Sets the background color of the tab bar.
324
325**Atomic service API**: This API can be used in atomic services since API version 11.
326
327**System capability**: SystemCapability.ArkUI.ArkUI.Full
328
329**Parameters**
330
331| Name| Type                                      | Mandatory| Description                                |
332| ------ | ------------------------------------------ | ---- | ------------------------------------ |
333| value  | [ResourceColor](ts-types.md#resourcecolor) | Yes  | Background color of the tab bar.<br>Default value: **Color.Transparent**|
334
335### barBackgroundBlurStyle<sup>11+</sup>
336
337barBackgroundBlurStyle(value: BlurStyle)
338
339Sets the background blur style of the tab bar.
340
341**Atomic service API**: This API can be used in atomic services since API version 11.
342
343**System capability**: SystemCapability.ArkUI.ArkUI.Full
344
345**Parameters**
346
347| Name| Type                                        | Mandatory| Description                                    |
348| ------ | -------------------------------------------- | ---- | ---------------------------------------- |
349| value  | [BlurStyle](ts-universal-attributes-background.md#blurstyle9) | Yes  | Background blur style of the tab bar.<br>Default value: **BlurStyle.NONE**|
350
351### barBackgroundBlurStyle<sup>18+</sup>
352
353barBackgroundBlurStyle(style: BlurStyle, options: BackgroundBlurStyleOptions)
354
355Defines the blur style to apply between the background and content of a tab bar. It encapsulates various blur radius, mask color, mask opacity, saturation, and brightness values through enum values.
356
357**Atomic service API**: This API can be used in atomic services since API version 18.
358
359**System capability**: SystemCapability.ArkUI.ArkUI.Full
360
361**Parameters**
362
363| Name               | Type                                                        | Mandatory| Description                                                        |
364| --------------------- | ------------------------------------------------------------ | ---- | ------------------------------------------------------------ |
365| style                 | [BlurStyle](ts-universal-attributes-background.md#blurstyle9)                 | Yes  | Settings of the background blur style, including the blur radius, mask color, mask opacity, saturation, and brightness.|
366| options | [BackgroundBlurStyleOptions](ts-universal-attributes-background.md#backgroundblurstyleoptions10) | Yes  | Background blur options.
367
368### barGridAlign<sup>10+</sup>
369
370barGridAlign(value: BarGridColumnOptions)
371
372Sets 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#breakpoints).
373
374**Atomic service API**: This API can be used in atomic services since API version 11.
375
376**System capability**: SystemCapability.ArkUI.ArkUI.Full
377
378**Parameters**
379
380| Name| Type                                                   | Mandatory| Description                              |
381| ------ | ------------------------------------------------------- | ---- | ---------------------------------- |
382| value  | [BarGridColumnOptions](#bargridcolumnoptions10) | Yes  | Visible area of the tab bar in grid mode.|
383
384### edgeEffect<sup>12+</sup>
385
386edgeEffect(edgeEffect: Optional&lt;EdgeEffect&gt;)
387
388Sets the edge effect used when the boundary of the scrolling area is reached.
389
390**Atomic service API**: This API can be used in atomic services since API version 12.
391
392**System capability**: SystemCapability.ArkUI.ArkUI.Full
393
394**Parameters**
395
396| Name| Type                                         | Mandatory| Description                                        |
397| ------ | --------------------------------------------- | ---- | -------------------------------------------- |
398| 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**|
399
400### barBackgroundEffect<sup>18+</sup>
401
402barBackgroundEffect(options: BackgroundEffectOptions)
403
404Sets the background effect of the tab bar, including the blur radius, brightness, saturation, and color.
405
406**Atomic service API**: This API can be used in atomic services since API version 18.
407
408**System capability**: SystemCapability.ArkUI.ArkUI.Full
409
410**Parameters**
411
412| Name | Type                                                        | Mandatory| Description                                      |
413| ------- | ------------------------------------------------------------ | ---- | ------------------------------------------ |
414| options | [BackgroundEffectOptions](ts-universal-attributes-background.md#backgroundeffectoptions11) | Yes  | Background effect options, including the blur radius, brightness, saturation, and color.|
415
416### pageFlipMode<sup>15+</sup>
417
418pageFlipMode(mode: Optional\<PageFlipMode>)
419
420Sets the mode for flipping pages using the mouse wheel.
421
422**Atomic service API**: This API can be used in atomic services since API version 15.
423
424**System capability**: SystemCapability.ArkUI.ArkUI.Full
425
426**Parameters**
427
428| Name| Type                                                       | Mandatory| Description                                                        |
429| ------ | ----------------------------------------------------------- | ---- | ------------------------------------------------------------ |
430| mode  | Optional\<[PageFlipMode](ts-appendix-enums.md#pageflipmode15)> | Yes  | Mode for flipping pages using the mouse wheel.<br>Default value: **PageFlipMode.CONTINUOUS**|
431
432### cachedMaxCount<sup>19+</sup>
433
434cachedMaxCount(count: number, mode: TabsCacheMode)
435
436Sets the maximum number of child components to cache and the caching mode. After this attribute is set, only child components outside the caching range will be released, while those within the range will not be preloaded.
437
438**Atomic service API**: This API can be used in atomic services since API version 19.
439
440**System capability**: SystemCapability.ArkUI.ArkUI.Full
441
442**Parameters**
443
444| Name| Type                                                       | Mandatory| Description                                                        |
445| ------ | ----------------------------------------------------------- | ---- | ------------------------------------------------------------ |
446| count  | number                                                      | Yes  | Maximum number of child components to cache. By default, all child components remain loaded and are not released.<br>Value range: [0, +∞)|
447| mode   | [TabsCacheMode](#tabscachemode19)                   | Yes  | Caching mode for child components.<br>Default value: **TabsCacheMode.CACHE_BOTH_SIDE**  |
448
449## DividerStyle<sup>10+</sup>
450
451Describes the divider style.
452
453**Atomic service API**: This API can be used in atomic services since API version 11.
454
455**System capability**: SystemCapability.ArkUI.ArkUI.Full
456
457| Name         | Type                                    | Mandatory  | Description                                      |
458| ----------- | ---------------------------------------- | ---- | ---------------------------------------- |
459| 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<br>Value range: [0, +∞)          |
460| color       | [ResourceColor](ts-types.md#resourcecolor) | No   | Color of the divider.<br>Default value: **#33182431**               |
461| 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<br>Value range: [0, +∞)|
462| 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<br>Value range: [0, +∞)|
463
464## BarGridColumnOptions<sup>10+</sup>
465
466Implements 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.
467
468**Atomic service API**: This API can be used in atomic services since API version 11.
469
470**System capability**: SystemCapability.ArkUI.ArkUI.Full
471
472| Name         | Type                                    | Mandatory  | Description                                      |
473| ----------- | ---------------------------------------- | ---- | ---------------------------------------- |
474| 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                       |
475| 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                    |
476| 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.|
477| 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.|
478| 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.|
479
480## ScrollableBarModeOptions<sup>10+</sup>
481
482Implements a **ScrollableBarModeOptions** object.
483
484**Atomic service API**: This API can be used in atomic services since API version 11.
485
486**System capability**: SystemCapability.ArkUI.ArkUI.Full
487
488| Name         | Type                                    | Mandatory  | Description                                      |
489| ----------- | ---------------------------------------- | ---- | ---------------------------------------- |
490| 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<br>Value range: [0, +∞)|
491| nonScrollableLayoutStyle      | [LayoutStyle](#layoutstyle10) | No   | Tab layout mode of the tab bar when not scrolling in scrollable mode.<br>Default value: **LayoutStyle.ALWAYS_CENTER**          |
492
493## BarMode
494
495Enumerates layout modes of the tab bar.
496
497**Atomic service API**: This API can be used in atomic services since API version 11.
498
499**System capability**: SystemCapability.ArkUI.ArkUI.Full
500
501| Name       | Value| Description                                    |
502| ---------- | -- | ---------------------------------------- |
503| 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.|
504| 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).|
505
506## AnimationMode<sup>12+</sup>
507
508Enumerates the animation modes for switching between tabs.
509
510**System capability**: SystemCapability.ArkUI.ArkUI.Full
511
512| Name         | Value  | Description                                                        |
513| ------------- | ---- | ------------------------------------------------------------ |
514| CONTENT_FIRST | 0    | Loads 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.|
515| ACTION_FIRST  | 1    | Starts the switching animation before loading the content of the target page. This mode works only when neither the height or width of tabs is set to **auto**.<br>**Atomic service API**: This API can be used in atomic services since API version 12.|
516| NO_ANIMATION  | 2    | Disables the default switching animation. Note that this mode is ineffective when the **changeIndex** API of **TabsController** is used to switch content.<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.|
517| CONTENT_FIRST_WITH_JUMP<sup>15+</sup> | 3    | Loads the content of the target page first, then jumps to the vicinity of the target page without animation, and finally jumps to the target page with animation.<br>**Atomic service API**: This API can be used in atomic services since API version 15.|
518| ACTION_FIRST_WITH_JUMP<sup>15+</sup>  | 4    | Jumps to the vicinity of the target page without animation first, then jumps to the target page with animation, and finally loads the content of the target page. This mode works only when neither the height or width of tabs is set to **auto**.<br>**Atomic service API**: This API can be used in atomic services since API version 15.|
519
520## LayoutStyle<sup>10+</sup>
521
522Enumerates the tab layout styles of the tab bar when not scrolling in scrollable mode.
523
524**Atomic service API**: This API can be used in atomic services since API version 11.
525
526**System capability**: SystemCapability.ArkUI.ArkUI.Full
527
528| Name        | Value| Description                                    |
529| ---------- | -- | ---------------------------------------- |
530| 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.|
531| 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.|
532| 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.|
533
534## CommonModifier<sup>15+</sup>
535
536type CommonModifier = CommonModifier
537
538Defines a parameter object for the **Tabs** component.
539
540**Atomic service API**: This API can be used in atomic services since API version 15.
541
542**System capability**: SystemCapability.ArkUI.ArkUI.Full
543
544| Type        | Description                                    |
545| ---------- | ---------------------------------------- |
546| [CommonModifier](ts-universal-attributes-attribute-modifier.md#attributemodifier) | Universal attributes for the tab bar.|
547
548## TabsCacheMode<sup>19+</sup>
549
550Caching mode for child components.
551
552**Atomic service API**: This API can be used in atomic services since API version 19.
553
554**System capability**: SystemCapability.ArkUI.ArkUI.Full
555
556| Name                 | Value| Description                                    |
557| --------------------- | -- | ---------------------------------------- |
558| CACHE_BOTH_SIDE       | 0  | Cache the currently displayed child component and the child components on both sides. For example, if **cachedMaxCount** is set to **n**, up to 2n+1 child components will be cached.|
559| CACHE_LATEST_SWITCHED | 1  | Cache the currently displayed child component and the most recently switched child component. For example, if **cachedMaxCount** is set to **n**, up to n+1 child components will be cached.|
560
561## Events
562
563In addition to the [universal events](ts-component-general-events.md), the following events are supported.
564
565### onChange
566
567onChange(event: Callback\<number>)
568
569Triggered after the active tab changes.
570
571This event is triggered when any of the following occurs:
572
5731. After completing a swipe-triggered tab switching animation.
574
5752. After the active tab changes by calling the [changeIndex](#changeindex) API of [Controller](#tabscontroller).
576
5773. After the active tab changes by updating the index through the bound [state variable](../../../ui/state-management/arkts-state.md).
578
5794. After the active tab changes by tapping a tab in the tab bar.
580
581>  **NOTE**
582>
583>  When a custom tab is used, relying solely on the **onChange** event for synchronization between tabs and swipe gestures may result in delayed visual updates, since it is triggered after the swipe-triggered tab switching animation is completed. For smooth animations, listen for the active tab index in [onAnimationStart](#onanimationstart11) and update the tab index accordingly. For details about the implementation, see [Example 3](#example-3-setting-up-custom-tab-switching-synchronization).
584
585**Atomic service API**: This API can be used in atomic services since API version 11.
586
587**System capability**: SystemCapability.ArkUI.ArkUI.Full
588
589**Parameters**
590
591| Name| Type  | Mandatory| Description                                  |
592| ------ | ------ | ---- | -------------------------------------- |
593| event  | [Callback](./ts-types.md#callback12)\<number> | Yes  | Index of the active tab. The index starts from 0.|
594
595### onTabBarClick<sup>10+</sup>
596
597onTabBarClick(event: Callback\<number>)
598
599Triggered when a tab is clicked.
600
601**Atomic service API**: This API can be used in atomic services since API version 11.
602
603**System capability**: SystemCapability.ArkUI.ArkUI.Full
604
605**Parameters**
606
607| Name| Type  | Mandatory| Description                                |
608| ------ | ------ | ---- | ------------------------------------ |
609| event  | [Callback](./ts-types.md#callback12)\<number> | Yes  | Index of the clicked tab. The index starts from 0.|
610
611### onAnimationStart<sup>11+</sup>
612
613onAnimationStart(handler: OnTabsAnimationStartCallback)
614
615Triggered when the tab switching animation starts. This event is not triggered when [animationDuration](#animationduration) is set to **0**, which effectively disables the animation.
616
617**Atomic service API**: This API can be used in atomic services since API version 12.
618
619**System capability**: SystemCapability.ArkUI.ArkUI.Full
620
621**Parameters**
622
623| Name| Type  | Mandatory| Description                |
624| ------ | ------ | ---- | -------------------- |
625| handler  | [OnTabsAnimationStartCallback](#ontabsanimationstartcallback18) | Yes  | Callback triggered when the switching animation starts.|
626
627### onAnimationEnd<sup>11+</sup>
628
629onAnimationEnd(handler: OnTabsAnimationEndCallback)
630
631Triggered when the tab switching animation is completed, including cases where the gesture is interrupted during animation. This event is not triggered when **animationDuration** is set to **0**, which effectively disables the animation.
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**Parameters**
638
639| Name| Type  | Mandatory| Description                |
640| ------ | ------ | ---- | -------------------- |
641| handler  | [OnTabsAnimationEndCallback](#ontabsanimationendcallback18) | Yes  | Callback triggered upon animation completion or interruption.|
642
643### onGestureSwipe<sup>11+</sup>
644
645onGestureSwipe(handler: OnTabsGestureSwipeCallback)
646
647Triggered on a frame-by-frame basis during swipe gestures for tab switching.
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**Parameters**
654
655| Name| Type  | Mandatory| Description                |
656| ------ | ------ | ---- | -------------------- |
657| handler  | [OnTabsGestureSwipeCallback](#ontabsgestureswipecallback18) | Yes  | Triggered on a frame-by-frame basis during swipe gestures for tab switching.|
658
659### customContentTransition<sup>11+</sup>
660
661customContentTransition(delegate: TabsCustomContentTransitionCallback)
662
663Sets the custom tab switching animation.
664
665Instructions:
666
6671. 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.
668
669**Atomic service API**: This API can be used in atomic services since API version 12.
670
671**System capability**: SystemCapability.ArkUI.ArkUI.Full
672
673**Parameters**
674
675| Name| Type  | Mandatory| Description                |
676| ------ | ------ | ---- | -------------------- |
677| delegate  | [TabsCustomContentTransitionCallback](#tabscustomcontenttransitioncallback18) | Yes  | Callback invoked when the custom tab switching animation starts.|
678
679
680### onContentWillChange<sup>12+</sup>
681
682onContentWillChange(handler: OnTabsContentWillChangeCallback)
683
684Triggered when a new page is about to be displayed.
685
686This event is triggered when any of the following occurs:
687
6881. When the user swipes through the **TabContent** to switch to a new page.
689
6902. When **TabsController.changeIndex** is called to switch to a new page.
691
6923. When the **index** attribute is changed to switch to a new page.
693
6944. When the user taps a tab on the tab bar to switch to a new page.
695
6965. When the user presses the left or right arrow key on the keyboard to switch to a new page while the tab bar has focus.
697
698**Atomic service API**: This API can be used in atomic services since API version 12.
699
700**System capability**: SystemCapability.ArkUI.ArkUI.Full
701
702**Parameters**
703
704| Name| Type  | Mandatory| Description                |
705| ------ | ------ | ---- | -------------------- |
706| handler  | [OnTabsContentWillChangeCallback](#ontabscontentwillchangecallback18) | Yes  | Callback invoked when a new page is about to be displayed.|
707
708### onSelected<sup>18+</sup>
709
710onSelected(event: Callback\<number>)
711
712Triggered when the selected element changes. The index of the currently selected element is returned.
713
714This event is triggered when any of the following occurs:
715
7161. When the swipe gesture is released and the tab switching threshold is met, triggering the switching animation.
717
7182. When the [changeIndex] (#changeindex) API of [TabsController](#tabscontroller) is called, triggering the switching animation.
719
7203. When the index of the active tab is changed through the bound [state variable](../../../ui/state-management/arkts-state.md).
721
7224. When a tab is tapped.
723
724**Atomic service API**: This API can be used in atomic services since API version 18.
725
726**System capability**: SystemCapability.ArkUI.ArkUI.Full
727
728**Parameters**
729
730| Name| Type  | Mandatory| Description                                  |
731| ------ | ------ | ---- | -------------------------------------- |
732| event  | [Callback](./ts-types.md#callback12)\<number> | Yes  | Index of the currently selected element.|
733
734> **NOTE**
735>
736> In the **onSelected** callback, the index of the current displayed page cannot be set using **index** of **TabsOptions**, and **TabsController.changeIndex()** cannot be called.
737
738### onUnselected<sup>18+</sup>
739
740onUnselected(event: Callback\<number>)
741
742Triggered when the selected element changes. The index of the element that is about to be hidden is returned.
743
744This event is triggered when any of the following occurs:
745
7461. When the swipe gesture is released and the tab switching threshold is met, triggering the switching animation.
747
7482. When the [changeIndex] (#changeindex) API of [TabsController](#tabscontroller) is called, triggering the switching animation.
749
7503. When the index of the active tab is changed through the bound [state variable](../../../ui/state-management/arkts-state.md).
751
7524. When a tab is tapped.
753
754**Atomic service API**: This API can be used in atomic services since API version 18.
755
756**System capability**: SystemCapability.ArkUI.ArkUI.Full
757
758**Parameters**
759
760| Name| Type  | Mandatory| Description                                  |
761| ------ | ------ | ---- | -------------------------------------- |
762| event  | [Callback](./ts-types.md#callback12)\<number> | Yes  | Index of the element that is about to be hidden.|
763
764> **NOTE**
765>
766> In the **onUnselected** callback, the index of the current displayed page cannot be set using **index** of **TabsOptions**, and **TabsController.changeIndex()** cannot be called.
767
768## OnTabsAnimationStartCallback<sup>18+</sup>
769
770type OnTabsAnimationStartCallback = (index: number, targetIndex: number, extraInfo: TabsAnimationEvent) => void
771
772Defines the callback triggered when the tab switching animation starts.
773
774**Atomic service API**: This API can be used in atomic services since API version 18.
775
776**System capability**: SystemCapability.ArkUI.ArkUI.Full
777
778**Parameters**
779
780| Name     | Type                                                  | Mandatory| Description                                                        |
781| ----------- | ------------------------------------------------------ | ---- | ------------------------------------------------------------ |
782| index       | number                                                 | Yes  | Index of the currently displayed element. The index is zero-based.                            |
783| targetIndex | number                                                 | Yes  | Index of the target element to switch to. The index is zero-based.                        |
784| extraInfo       | [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.|
785
786## OnTabsAnimationEndCallback<sup>18+</sup>
787
788type OnTabsAnimationEndCallback = (index: number, extraInfo: TabsAnimationEvent) => void
789
790Defines the callback triggered when the tab switching animation ends.
791
792**Atomic service API**: This API can be used in atomic services since API version 18.
793
794**System capability**: SystemCapability.ArkUI.ArkUI.Full
795
796**Parameters**
797
798| Name| Type                                                  | Mandatory| Description                                                        |
799| ------ | ------------------------------------------------------ | ---- | ------------------------------------------------------------ |
800| index  | number                                                 | Yes  | Index of the currently displayed element. The index is zero-based.                                   |
801| extraInfo  | [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.|
802
803## OnTabsGestureSwipeCallback<sup>18+</sup>
804
805type OnTabsGestureSwipeCallback = (index: number, extraInfo: TabsAnimationEvent) => void
806
807Defines the callback invoked on a frame-by-frame basis when the page is turned by a swipe.
808
809**Atomic service API**: This API can be used in atomic services since API version 18.
810
811**System capability**: SystemCapability.ArkUI.ArkUI.Full
812
813**Parameters**
814
815| Name| Type                                                  | Mandatory| Description                                                        |
816| ------ | ------------------------------------------------------ | ---- | ------------------------------------------------------------ |
817| index  | number                                                 | Yes  | Index of the currently displayed element. The index is zero-based.                                   |
818| extraInfo  | [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.|
819
820## TabsCustomContentTransitionCallback<sup>18+</sup>
821
822type TabsCustomContentTransitionCallback = (from: number, to: number) => TabContentAnimatedTransition | undefined
823
824Defines the callback invoked when the custom tab switching animation starts.
825
826**Atomic service API**: This API can be used in atomic services since API version 18.
827
828**System capability**: SystemCapability.ArkUI.ArkUI.Full
829
830**Parameters**
831
832| Name| Type  | Mandatory| Description                           |
833| ------ | ------ | ---- | ------------------------------- |
834| from   | number | Yes  | Index of the currently displayed tab before the animation starts. The index is zero-based.|
835| to     | number | Yes  | Index of the target tab before the animation starts. The index is zero-based.|
836
837**Return value**
838
839| Type                                                        | Description                    |
840| ------------------------------------------------------------ | ------------------------ |
841| [TabContentAnimatedTransition](#tabcontentanimatedtransition11) \| undefined | Information about the custom tab switching animation.|
842
843## OnTabsContentWillChangeCallback<sup>18+</sup>
844
845type OnTabsContentWillChangeCallback = (currentIndex: number, comingIndex: number) => boolean
846
847Defines the callback invoked when a new page is about to be displayed.
848
849**Atomic service API**: This API can be used in atomic services since API version 18.
850
851**System capability**: SystemCapability.ArkUI.ArkUI.Full
852
853**Parameters**
854
855| Name      | Type  | Mandatory| Description                                      |
856| ------------ | ------ | ---- | ------------------------------------------ |
857| currentIndex | number | Yes  | Index of the active tab. The index starts from 0.|
858| comingIndex  | number | Yes  | Index of the new tab to be displayed.             |
859
860**Return value**
861
862| Type   | Description                                                        |
863| ------- | ------------------------------------------------------------ |
864| 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.|
865
866## TabsAnimationEvent<sup>11+</sup>
867
868Describes the animation information of the **Tabs** component.
869
870**Atomic service API**: This API can be used in atomic services since API version 12.
871
872**System capability**: SystemCapability.ArkUI.ArkUI.Full
873
874| Name           | Type     | Read Only| Optional| Description                                      |
875| ------------- | ---------- | ---- | ---- | ------------------------ |
876| 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**.|
877| 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**.|
878| velocity | number | No| No| Hands-off velocity at the beginning of the animation. Unit: vp/s.<br>Default value: **0**.|
879
880## TabContentAnimatedTransition<sup>11+</sup>
881
882Provides the information about the custom tab switching animation.
883
884**Widget capability**: This API can be used in ArkTS widgets since API version 11.
885
886**Atomic service API**: This API can be used in atomic services since API version 12.
887
888**System capability**: SystemCapability.ArkUI.ArkUI.Full
889
890| Name           | Type        | Mandatory  | Description                                      |
891| ------------- | ---------------------- | ---- |---------------------- |
892| timeout | number | No| Timeout for the custom tab 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.<br>Default value: **1000**<br>Unit: ms<br>Value range: [0, +∞)|
893| transition | [Callback](./ts-types.md#callback12)\<[TabContentTransitionProxy](#tabcontenttransitionproxy11)> | Yes| Content of the custom tab switching animation.|
894
895## TabContentTransitionProxy<sup>11+</sup>
896
897Implements 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.
898
899**Widget capability**: This API can be used in ArkTS widgets since API version 11.
900
901**Atomic service API**: This API can be used in atomic services since API version 12.
902
903**System capability**: SystemCapability.ArkUI.ArkUI.Full
904
905### Attributes
906
907| Name | Type    | Read Only| Optional| Description                        |
908| ----- | ------- | ---- | ---- | --------------------------- |
909| from | number | No| No| Zero-based index of the source page in the custom animation.|
910| to | number | No| No| Zero-based index of the target page in the custom animation.|
911
912### finishTransition
913
914finishTransition(): void
915
916Notifies the **Tabs** component that the custom animation has finished playing.
917
918**Widget capability**: This API can be used in ArkTS widgets since API version 11.
919
920**Atomic service API**: This API can be used in atomic services since API version 12.
921
922**System capability**: SystemCapability.ArkUI.ArkUI.Full
923
924## TabsController
925
926Defines a tab controller, which is used to control switching of tabs. One **TabsController** cannot control multiple **Tabs** components.
927
928**Atomic service API**: This API can be used in atomic services since API version 11.
929
930**System capability**: SystemCapability.ArkUI.ArkUI.Full
931
932### constructor
933
934constructor()
935
936A constructor used to create a **TabsController** object.
937
938**Atomic service API**: This API can be used in atomic services since API version 11.
939
940**System capability**: SystemCapability.ArkUI.ArkUI.Full
941
942### changeIndex
943
944changeIndex(value: number): void
945
946Switches to the specified tab.
947
948**Atomic service API**: This API can be used in atomic services since API version 11.
949
950**System capability**: SystemCapability.ArkUI.ArkUI.Full
951
952**Parameters**
953
954| Name  | Type  | Mandatory  | Description                                    |
955| ----- | ------ | ---- | ---------------------------------------- |
956| 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.|
957
958### preloadItems<sup>12+</sup>
959
960preloadItems(indices: Optional\<Array\<number>>): Promise\<void>
961
962Preloads 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.
963
964**Atomic service API**: This API can be used in atomic services since API version 12.
965
966**System capability**: SystemCapability.ArkUI.ArkUI.Full
967
968**Parameters**
969
970| Name  | Type  | Mandatory  | Description                                    |
971| ----- | ------ | ---- | ---------------------------------------- |
972| indices | Optional\<Array\<number>> | Yes| Array of indexes of the child nodes to preload.<br>The default value is an empty array.|
973
974**Return value**
975
976| Type                                                        | Description                    |
977| ------------------------------------------------------------ | ------------------------ |
978| Promise\<void> | Promise used to return the value.|
979
980**Error codes**
981
982For details about the error codes, see [Universal Error Codes](../../errorcode-universal.md).
983
984| ID  | Error Message                                     |
985| --------   | -------------------------------------------- |
986| 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. |
987
988### setTabBarTranslate<sup>13+</sup>
989
990setTabBarTranslate(translate: TranslateOptions): void
991
992Sets the translation distance of the tab bar.
993
994> **NOTE**
995>
996> When a **Tabs** component is bound to a scrollable container using APIs like [bindTabsToScrollable](../js-apis-arkui-UIContext.md#bindtabstoscrollable13) or [bindTabsToNestedScrollable](../js-apis-arkui-UIContext.md#bindtabstonestedscrollable13), 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.
997>
998
999**Atomic service API**: This API can be used in atomic services since API version 13.
1000
1001**System capability**: SystemCapability.ArkUI.ArkUI.Full
1002
1003**Parameters**
1004
1005| Name  | Type  | Mandatory  | Description                                    |
1006| ----- | ------ | ---- | ---------------------------------------- |
1007| translate | [TranslateOptions](ts-universal-attributes-transformation.md#translateoptions) | Yes| Translation distance of the tab bar.|
1008
1009### setTabBarOpacity<sup>13+</sup>
1010
1011setTabBarOpacity(opacity: number): void
1012
1013Sets the opacity of the tab bar.
1014
1015> **NOTE**
1016>
1017> When a **Tabs** component is bound to a scrollable container using APIs like [bindTabsToScrollable](../js-apis-arkui-UIContext.md#bindtabstoscrollable13) or [bindTabsToNestedScrollable](../js-apis-arkui-UIContext.md#bindtabstonestedscrollable13), 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.
1018>
1019
1020**Atomic service API**: This API can be used in atomic services since API version 13.
1021
1022**System capability**: SystemCapability.ArkUI.ArkUI.Full
1023
1024**Parameters**
1025
1026| Name  | Type  | Mandatory  | Description                                    |
1027| ----- | ------ | ---- | ---------------------------------------- |
1028| opacity | number | Yes| Opacity of the tab bar. The value range is [0.0, 1.0].|
1029
1030## Example
1031
1032### Example 1: Setting the Tab Bar Layout Mode
1033
1034This example shows how to use **barMode** to implement two tab bar layouts: equal-width tab layout and actual-length-based layout. It also shows the scrollable effect when the combined width of tabs exceeds the tab bar container width.
1035
1036```ts
1037// xxx.ets
1038@Entry
1039@Component
1040struct TabsExample {
1041  @State text: string = 'Text';
1042  @State barMode: BarMode = BarMode.Fixed;
1043
1044  build() {
1045    Column() {
1046      Row() {
1047        Button('Add Text')
1048          .width('47%')
1049          .height(50)
1050          .onClick((event?: ClickEvent) => {
1051            this.text += 'Add Text';
1052          })
1053          .margin({ right: '6%', bottom: '12vp' })
1054
1055        Button('Reset Text')
1056          .width('47%')
1057          .height(50)
1058          .onClick((event?: ClickEvent) => {
1059            this.text = 'Text';
1060          })
1061          .margin({ bottom: '12vp' })
1062      }
1063
1064      Row() {
1065        Button('BarMode.Fixed')
1066          .width('47%')
1067          .height(50)
1068          .onClick((event?: ClickEvent) => {
1069            this.barMode = BarMode.Fixed;
1070          })
1071          .margin({ right: '6%', bottom: '12vp' })
1072
1073        Button('BarMode.Scrollable')
1074          .width('47%')
1075          .height(50)
1076          .onClick((event?: ClickEvent) => {
1077            this.barMode = BarMode.Scrollable;
1078          })
1079          .margin({ bottom: '12vp' })
1080      }
1081
1082      Tabs() {
1083        TabContent() {
1084          Column().width('100%').height('100%').backgroundColor(Color.Pink)
1085        }.tabBar(SubTabBarStyle.of(this.text))
1086
1087        TabContent() {
1088          Column().width('100%').height('100%').backgroundColor(Color.Green)
1089        }.tabBar(SubTabBarStyle.of(this.text))
1090
1091        TabContent() {
1092          Column().width('100%').height('100%').backgroundColor(Color.Blue)
1093        }.tabBar(SubTabBarStyle.of(this.text))
1094      }
1095      .height('60%')
1096      .backgroundColor(0xf1f3f5)
1097      .barMode(this.barMode)
1098    }
1099    .width('100%')
1100    .height(500)
1101    .padding('24vp')
1102  }
1103}
1104```
1105
1106
1107### Example 2: Setting the Layout Style for a Scrollable TabBar
1108
1109This example implements the **ScrollableBarModeOptions** parameter of **barMode**. This parameter is effective only in **Scrollable** mode.
1110
1111```ts
1112// xxx.ets
1113@Entry
1114@Component
1115struct TabsExample6 {
1116  private controller: TabsController = new TabsController();
1117  @State scrollMargin: number = 0;
1118  @State layoutStyle: LayoutStyle = LayoutStyle.ALWAYS_CENTER;
1119  @State text: string = 'Text';
1120
1121  build() {
1122    Column() {
1123      Row() {
1124        Button('scrollMargin+10 ' + this.scrollMargin)
1125          .width('47%')
1126          .height(50)
1127          .margin({ top: 5 })
1128          .onClick((event?: ClickEvent) => {
1129            this.scrollMargin += 10;
1130          })
1131          .margin({ right: '6%', bottom: '12vp' })
1132        Button('scrollMargin-10 ' + this.scrollMargin)
1133          .width('47%')
1134          .height(50)
1135          .margin({ top: 5 })
1136          .onClick((event?: ClickEvent) => {
1137            this.scrollMargin -= 10;
1138          })
1139          .margin({ bottom: '12vp' })
1140      }
1141
1142      Row() {
1143        Button('Add Text')
1144          .width('47%')
1145          .height(50)
1146          .margin({ top: 5 })
1147          .onClick((event?: ClickEvent) => {
1148            this.text += 'Add Text';
1149          })
1150          .margin({ right: '6%', bottom: '12vp' })
1151        Button('Reset Text')
1152          .width('47%')
1153          .height(50)
1154          .margin({ top: 5 })
1155          .onClick((event?: ClickEvent) => {
1156            this.text = 'Text';
1157          })
1158          .margin({ bottom: '12vp' })
1159      }
1160
1161      Row() {
1162        Button('layoutStyle.ALWAYS_CENTER')
1163          .width('100%')
1164          .height(50)
1165          .margin({ top: 5 })
1166          .fontSize(15)
1167          .onClick((event?: ClickEvent) => {
1168            this.layoutStyle = LayoutStyle.ALWAYS_CENTER;
1169          })
1170          .margin({ bottom: '12vp' })
1171      }
1172
1173      Row() {
1174        Button('layoutStyle.ALWAYS_AVERAGE_SPLIT')
1175          .width('100%')
1176          .height(50)
1177          .margin({ top: 5 })
1178          .fontSize(15)
1179          .onClick((event?: ClickEvent) => {
1180            this.layoutStyle = LayoutStyle.ALWAYS_AVERAGE_SPLIT;
1181          })
1182          .margin({ bottom: '12vp' })
1183      }
1184
1185      Row() {
1186        Button('layoutStyle.SPACE_BETWEEN_OR_CENTER')
1187          .width('100%')
1188          .height(50)
1189          .margin({ top: 5 })
1190          .fontSize(15)
1191          .onClick((event?: ClickEvent) => {
1192            this.layoutStyle = LayoutStyle.SPACE_BETWEEN_OR_CENTER;
1193          })
1194          .margin({ bottom: '12vp' })
1195      }
1196
1197      Tabs({ barPosition: BarPosition.End, controller: this.controller }) {
1198        TabContent() {
1199          Column().width('100%').height('100%').backgroundColor(Color.Pink)
1200        }.tabBar(SubTabBarStyle.of(this.text))
1201
1202        TabContent() {
1203          Column().width('100%').height('100%').backgroundColor(Color.Green)
1204        }.tabBar(SubTabBarStyle.of(this.text))
1205
1206        TabContent() {
1207          Column().width('100%').height('100%').backgroundColor(Color.Blue)
1208        }.tabBar(SubTabBarStyle.of(this.text))
1209      }
1210      .animationDuration(300)
1211      .height('60%')
1212      .backgroundColor(0xf1f3f5)
1213      .barMode(BarMode.Scrollable, { margin: this.scrollMargin, nonScrollableLayoutStyle: this.layoutStyle })
1214    }
1215    .width('100%')
1216    .height(500)
1217    .margin({ top: 5 })
1218    .padding('24vp')
1219  }
1220}
1221```
1222
1223
1224
1225### Example 3: Implementing Custom Tab Switching Synchronization
1226
1227This example demonstrates how to use **onAnimationStart** and **onChange** to synchronize tabs with swiping gestures during tab switching.
1228
1229```ts
1230// xxx.ets
1231@Entry
1232@Component
1233struct TabsExample {
1234  @State fontColor: string = '#182431';
1235  @State selectedFontColor: string = '#007DFF';
1236  @State currentIndex: number = 0;
1237  @State selectedIndex: number = 0;
1238  private controller: TabsController = new TabsController();
1239
1240  @Builder tabBuilder(index: number, name: string) {
1241    Column() {
1242      Text(name)
1243        .fontColor(this.selectedIndex === index ? this.selectedFontColor : this.fontColor)
1244        .fontSize(16)
1245        .fontWeight(this.selectedIndex === index ? 500 : 400)
1246        .lineHeight(22)
1247        .margin({ top: 17, bottom: 7 })
1248      Divider()
1249        .strokeWidth(2)
1250        .color('#007DFF')
1251        .opacity(this.selectedIndex === index ? 1 : 0)
1252    }.width('100%')
1253  }
1254
1255  build() {
1256    Column() {
1257      Tabs({ barPosition: BarPosition.Start, index: this.currentIndex, controller: this.controller }) {
1258        TabContent() {
1259          Column().width('100%').height('100%').backgroundColor('#00CB87')
1260        }.tabBar(this.tabBuilder(0, 'green'))
1261
1262        TabContent() {
1263          Column().width('100%').height('100%').backgroundColor('#007DFF')
1264        }.tabBar(this.tabBuilder(1, 'blue'))
1265
1266        TabContent() {
1267          Column().width('100%').height('100%').backgroundColor('#FFBF00')
1268        }.tabBar(this.tabBuilder(2, 'yellow'))
1269
1270        TabContent() {
1271          Column().width('100%').height('100%').backgroundColor('#E67C92')
1272        }.tabBar(this.tabBuilder(3, 'pink'))
1273      }
1274      .vertical(false)
1275      .barMode(BarMode.Fixed)
1276      .barWidth(360)
1277      .barHeight(56)
1278      .animationDuration(400)
1279      .onChange((index: number) => {
1280        // currentIndex controls which tab is displayed.
1281        this.currentIndex = index;
1282        this.selectedIndex = index;
1283      })
1284      .onAnimationStart((index: number, targetIndex: number, event: TabsAnimationEvent) => {
1285        if (index === targetIndex) {
1286          return;
1287        }
1288        // selectedIndex controls the color switching for the image and text in the custom tab bar.
1289        this.selectedIndex = targetIndex;
1290      })
1291      .width(360)
1292      .height(296)
1293      .margin({ top: 52 })
1294      .backgroundColor('#F1F3F5')
1295    }.width('100%')
1296  }
1297}
1298```
1299
1300![tabs3](figures/tabs_onAnimationStart.gif)
1301
1302### Example 4: Setting the Basic Attributes of the Divider
1303
1304This example uses **divider** to present dividers in different styles.
1305
1306```ts
1307// xxx.ets
1308@Entry
1309@Component
1310struct TabsDivider1 {
1311  private controller1: TabsController = new TabsController();
1312  @State dividerColor: string = 'red';
1313  @State strokeWidth: number = 2;
1314  @State startMargin: number = 0;
1315  @State endMargin: number = 0;
1316  @State nullFlag: boolean = false;
1317
1318  build() {
1319    Column() {
1320      Tabs({ controller: this.controller1 }) {
1321        TabContent() {
1322          Column().width('100%').height('100%').backgroundColor(Color.Pink)
1323        }.tabBar('pink')
1324
1325        TabContent() {
1326          Column().width('100%').height('100%').backgroundColor(Color.Yellow)
1327        }.tabBar('yellow')
1328
1329        TabContent() {
1330          Column().width('100%').height('100%').backgroundColor(Color.Blue)
1331        }.tabBar('blue')
1332
1333        TabContent() {
1334          Column().width('100%').height('100%').backgroundColor(Color.Green)
1335        }.tabBar('green')
1336
1337        TabContent() {
1338          Column().width('100%').height('100%').backgroundColor(Color.Red)
1339        }.tabBar('red')
1340      }
1341      .vertical(true)
1342      .scrollable(true)
1343      .barMode(BarMode.Fixed)
1344      .barWidth(70)
1345      .barHeight(200)
1346      .animationDuration(400)
1347      .onChange((index: number) => {
1348        console.info(index.toString());
1349      })
1350      .height('200vp')
1351      .margin({ bottom: '12vp' })
1352      .divider(this.nullFlag ? null : {
1353        strokeWidth: this.strokeWidth,
1354        color: this.dividerColor,
1355        startMargin: this.startMargin,
1356        endMargin: this.endMargin
1357      })
1358
1359      Button('Regular Divider').width('100%').margin({ bottom: '12vp' })
1360        .onClick(() => {
1361          this.nullFlag = false;
1362          this.strokeWidth = 2;
1363          this.dividerColor = 'red';
1364          this.startMargin = 0;
1365          this.endMargin = 0;
1366        })
1367      Button('Empty Divider').width('100%').margin({ bottom: '12vp' })
1368        .onClick(() => {
1369          this.nullFlag = true;
1370        })
1371      Button('Change to Blue').width('100%').margin({ bottom: '12vp'})
1372        .onClick(() => {
1373          this.dividerColor = 'blue';
1374        })
1375      Button('Increase Width').width('100%').margin({ bottom: '12vp' })
1376        .onClick(() => {
1377          this.strokeWidth += 2;
1378        })
1379      Button('Decrease Width').width('100%').margin({ bottom: '12vp'})
1380        .onClick(() => {
1381          if (this.strokeWidth > 2) {
1382            this.strokeWidth -= 2;
1383          }
1384        })
1385      Button('Increase Top Margin').width('100%').margin({ bottom: '12vp' })
1386        .onClick(() => {
1387          this.startMargin += 2;
1388        })
1389      Button('Decrease Top Margin').width('100%').margin({ bottom: '12vp' })
1390        .onClick(() => {
1391          if (this.startMargin > 2) {
1392            this.startMargin -= 2;
1393          }
1394        })
1395      Button ('Increase Bottom Margin').width ('100%').margin ({ bottom:'12vp'})
1396        .onClick(() => {
1397          this.endMargin += 2;
1398        })
1399      Button ('Decrease Bottom Margin').width ('100%').margin ({ bottom:'12vp' })
1400        .onClick(() => {
1401          if (this.endMargin > 2) {
1402            this.endMargin -= 2;
1403          }
1404        })
1405    }.padding({ top: '24vp', left: '24vp', right: '24vp' })
1406  }
1407}
1408```
1409
1410![tabs4](figures/tabs_divider.gif)
1411
1412### Example 5: Setting Tab Bar Fading
1413
1414This example uses **fadingEdge** to specify whether to fade out tabs.
1415
1416```ts
1417// xxx.ets
1418@Entry
1419@Component
1420struct TabsOpaque {
1421  @State message: string = 'Hello World';
1422  private controller: TabsController = new TabsController();
1423  private controller1: TabsController = new TabsController();
1424  @State selfFadingFade: boolean = true;
1425
1426  build() {
1427    Column() {
1428      Button('Set Tab to Fade').width('100%').margin({ bottom: '12vp' })
1429        .onClick((event?: ClickEvent) => {
1430          this.selfFadingFade = true;
1431        })
1432      Button('Set Tab Not to Fade').width('100%').margin({ bottom: '12vp' })
1433        .onClick((event?: ClickEvent) => {
1434          this.selfFadingFade = false;
1435        })
1436      Tabs({ barPosition: BarPosition.End, controller: this.controller }) {
1437        TabContent() {
1438          Column().width('100%').height('100%').backgroundColor(Color.Pink)
1439        }.tabBar('pink')
1440
1441        TabContent() {
1442          Column().width('100%').height('100%').backgroundColor(Color.Yellow)
1443        }.tabBar('yellow')
1444
1445        TabContent() {
1446          Column().width('100%').height('100%').backgroundColor(Color.Blue)
1447        }.tabBar('blue')
1448
1449        TabContent() {
1450          Column().width('100%').height('100%').backgroundColor(Color.Green)
1451        }.tabBar('green')
1452
1453        TabContent() {
1454          Column().width('100%').height('100%').backgroundColor(Color.Green)
1455        }.tabBar('green')
1456
1457        TabContent() {
1458          Column().width('100%').height('100%').backgroundColor(Color.Green)
1459        }.tabBar('green')
1460
1461        TabContent() {
1462          Column().width('100%').height('100%').backgroundColor(Color.Green)
1463        }.tabBar('green')
1464
1465        TabContent() {
1466          Column().width('100%').height('100%').backgroundColor(Color.Green)
1467        }.tabBar('green')
1468      }
1469      .vertical(false)
1470      .scrollable(true)
1471      .barMode(BarMode.Scrollable)
1472      .barHeight(80)
1473      .animationDuration(400)
1474      .onChange((index: number) => {
1475        console.info(index.toString());
1476      })
1477      .fadingEdge(this.selfFadingFade)
1478      .height('30%')
1479      .width('100%')
1480
1481      Tabs({ barPosition: BarPosition.Start, controller: this.controller1 }) {
1482        TabContent() {
1483          Column().width('100%').height('100%').backgroundColor(Color.Pink)
1484        }.tabBar('pink')
1485
1486        TabContent() {
1487          Column().width('100%').height('100%').backgroundColor(Color.Yellow)
1488        }.tabBar('yellow')
1489
1490        TabContent() {
1491          Column().width('100%').height('100%').backgroundColor(Color.Blue)
1492        }.tabBar('blue')
1493
1494        TabContent() {
1495          Column().width('100%').height('100%').backgroundColor(Color.Green)
1496        }.tabBar('green')
1497
1498        TabContent() {
1499          Column().width('100%').height('100%').backgroundColor(Color.Green)
1500        }.tabBar('green')
1501
1502        TabContent() {
1503          Column().width('100%').height('100%').backgroundColor(Color.Green)
1504        }.tabBar('green')
1505      }
1506      .vertical(true)
1507      .scrollable(true)
1508      .barMode(BarMode.Scrollable)
1509      .barHeight(200)
1510      .barWidth(80)
1511      .animationDuration(400)
1512      .onChange((index: number) => {
1513        console.info(index.toString());
1514      })
1515      .fadingEdge(this.selfFadingFade)
1516      .height('30%')
1517      .width('100%')
1518    }
1519    .padding({ top: '24vp', left: '24vp', right: '24vp' })
1520  }
1521}
1522```
1523
1524
1525
1526### Example 6: Implementing TabBar Overlay on TabContent
1527
1528This example shows how to use **barOverlap** to specify whether the tab bar overlaps the **TabContent** component with a blurred background effect.
1529
1530```ts
1531// xxx.ets
1532@Entry
1533@Component
1534struct barHeightTest {
1535  @State arr: number[] = [0, 1, 2, 3];
1536  @State barOverlap: boolean = true;
1537
1538  build() {
1539    Column() {
1540      Text(`barOverlap ${this.barOverlap}`).fontSize(16)
1541      Button('Change barOverlap').width('100%').margin({ bottom: '12vp' })
1542        .onClick((event?: ClickEvent) => {
1543          if (this.barOverlap) {
1544            this.barOverlap = false;
1545          } else {
1546            this.barOverlap = true;
1547          }
1548        })
1549
1550      Tabs({ barPosition: BarPosition.End }) {
1551        TabContent() {
1552          Column() {
1553            List({ space: 10 }) {
1554              ForEach(this.arr, (item: number) => {
1555                ListItem() {
1556                  Text('item' + item).width('80%').height(200).fontSize(16).textAlign(TextAlign.Center).backgroundColor('#fff8b81e')
1557                }
1558              }, (item: string) => item)
1559            }.width('100%').height('100%')
1560            .lanes(2).alignListItem(ListItemAlign.Center)
1561          }.width('100%').height('100%')
1562          .backgroundColor(Color.Pink)
1563        }
1564        .tabBar(new BottomTabBarStyle($r('sys.media.ohos_icon_mask_svg'), 'test 0'))
1565      }
1566      .scrollable(false)
1567      .height('60%')
1568      .barOverlap(this.barOverlap)
1569    }
1570    .height(500)
1571    .padding({ top: '24vp', left: '24vp', right: '24vp' })
1572  }
1573}
1574```
1575
1576
1577
1578### Example 7: Setting the Visible Area for the Tab Bar in Responsive Grid Mode
1579
1580This example uses **barGridAlign** to set the visible area of the tab bar in responsive grid mode.
1581
1582```ts
1583// xxx.ets
1584@Entry
1585@Component
1586struct TabsExample5 {
1587  private controller: TabsController = new TabsController();
1588  @State gridMargin: number = 10;
1589  @State gridGutter: number = 10;
1590  @State sm: number = -2;
1591  @State clickedContent: string = '';
1592
1593  build() {
1594    Column() {
1595      Row() {
1596        Button('gridMargin+10 ' + this.gridMargin)
1597          .width('47%')
1598          .height(50)
1599          .margin({ top: 5 })
1600          .onClick((event?: ClickEvent) => {
1601            this.gridMargin += 10;
1602          })
1603          .margin({ right: '6%', bottom: '12vp' })
1604        Button('gridMargin-10 ' + this.gridMargin)
1605          .width('47%')
1606          .height(50)
1607          .margin({ top: 5 })
1608          .onClick((event?: ClickEvent) => {
1609            this.gridMargin -= 10;
1610          })
1611          .margin({ bottom: '12vp' })
1612      }
1613
1614      Row() {
1615        Button('gridGutter+10 ' + this.gridGutter)
1616          .width('47%')
1617          .height(50)
1618          .margin({ top: 5 })
1619          .onClick((event?: ClickEvent) => {
1620            this.gridGutter += 10;
1621          })
1622          .margin({ right: '6%', bottom: '12vp' })
1623        Button('gridGutter-10 ' + this.gridGutter)
1624          .width('47%')
1625          .height(50)
1626          .margin({ top: 5 })
1627          .onClick((event?: ClickEvent) => {
1628            this.gridGutter -= 10;
1629          })
1630          .margin({ bottom: '12vp' })
1631      }
1632
1633      Row() {
1634        Button('sm+2 ' + this.sm)
1635          .width('47%')
1636          .height(50)
1637          .margin({ top: 5 })
1638          .onClick((event?: ClickEvent) => {
1639            this.sm += 2;
1640          })
1641          .margin({ right: '6%' })
1642        Button('sm-2 ' + this.sm).width('47%').height(50).margin({ top: 5 })
1643          .onClick((event?: ClickEvent) => {
1644            this.sm -= 2;
1645          })
1646      }
1647
1648      Text('Tapped content: ' + this.clickedContent).width('100%').height(200).margin({ top: 5 })
1649
1650
1651      Tabs({ barPosition: BarPosition.End, controller: this.controller }) {
1652        TabContent() {
1653          Column().width('100%').height('100%').backgroundColor(Color.Pink)
1654        }.tabBar(BottomTabBarStyle.of($r('sys.media.ohos_app_icon'), '1'))
1655
1656        TabContent() {
1657          Column().width('100%').height('100%').backgroundColor(Color.Green)
1658        }.tabBar(BottomTabBarStyle.of($r('sys.media.ohos_app_icon'), '2'))
1659
1660        TabContent() {
1661          Column().width('100%').height('100%').backgroundColor(Color.Blue)
1662        }.tabBar(BottomTabBarStyle.of($r('sys.media.ohos_app_icon'), '3'))
1663      }
1664      .width('350vp')
1665      .animationDuration(300)
1666      .height('60%')
1667      .barGridAlign({ sm: this.sm, margin: this.gridMargin, gutter: this.gridGutter })
1668      .backgroundColor(0xf1f3f5)
1669      .onTabBarClick((index: number) => {
1670        this.clickedContent += 'now index ' + index + ' is clicked\n';
1671      })
1672    }
1673    .width('100%')
1674    .height(500)
1675    .margin({ top: 5 })
1676    .padding('10vp')
1677  }
1678}
1679```
1680
1681![tabs7](figures/tabs_barGridAlign.gif)
1682
1683### Example 8: Implementing a Custom Tab Switching Animation
1684
1685This example uses **customContentTransition** to implement a custom tab switching animation.
1686
1687```ts
1688// xxx.ets
1689interface itemType {
1690  text: string,
1691  backgroundColor: Color
1692}
1693
1694@Entry
1695@Component
1696struct TabsCustomAnimationExample {
1697  @State data: itemType[] = [
1698    {
1699      text: 'Red',
1700      backgroundColor: Color.Red
1701    },
1702    {
1703      text: 'Yellow',
1704      backgroundColor: Color.Yellow
1705    },
1706    {
1707      text: 'Blue',
1708      backgroundColor: Color.Blue
1709    }];
1710  @State opacityList: number[] = [];
1711  @State scaleList: number[] = [];
1712
1713  private durationList: number[] = [];
1714  private timeoutList: number[] = [];
1715  private customContentTransition: (from: number, to: number) => TabContentAnimatedTransition = (from: number, to: number) => {
1716    let tabContentAnimatedTransition = {
1717      timeout: this.timeoutList[from],
1718      transition: (proxy: TabContentTransitionProxy) => {
1719        this.scaleList[from] = 1.0;
1720        this.scaleList[to] = 0.5;
1721        this.opacityList[from] = 1.0;
1722        this.opacityList[to] = 0.5;
1723        this.getUIContext()?.animateTo({
1724          duration: this.durationList[from],
1725          onFinish: () => {
1726            proxy.finishTransition();
1727          }
1728        }, () => {
1729          this.scaleList[from] = 0.5;
1730          this.scaleList[to] = 1.0;
1731          this.opacityList[from] = 0.5;
1732          this.opacityList[to] = 1.0;
1733        });
1734      }
1735    } as TabContentAnimatedTransition;
1736    return tabContentAnimatedTransition;
1737  };
1738
1739  aboutToAppear(): void {
1740    let duration = 1000;
1741    let timeout = 1000;
1742    for (let i = 1; i <= this.data.length; i++) {
1743      this.opacityList.push(1.0);
1744      this.scaleList.push(1.0);
1745      this.durationList.push(duration * i);
1746      this.timeoutList.push(timeout * i);
1747    }
1748  }
1749
1750  build() {
1751    Column() {
1752      Tabs() {
1753        ForEach(this.data, (item: itemType, index: number) => {
1754          TabContent() {}
1755          .tabBar(item.text)
1756          .backgroundColor(item.backgroundColor)
1757          // Customize the opacity and scale animation.
1758          .opacity(this.opacityList[index])
1759          .scale({ x: this.scaleList[index], y: this.scaleList[index] })
1760        })
1761      }
1762      .backgroundColor(0xf1f3f5)
1763      .width('100%')
1764      .height(500)
1765      .customContentTransition(this.customContentTransition)
1766    }
1767  }
1768}
1769```
1770
1771![tabs8](figures/tabs8.gif)
1772
1773### Example 9: Implementing Tab Switching Interception
1774
1775This example uses **onContentWillChange** to implement custom swipe-based tab switching interception.
1776
1777```ts
1778//xxx.ets
1779@Entry
1780@Component
1781struct TabsExample {
1782  @State selectedIndex: number = 2;
1783  @State currentIndex: number = 2;
1784  private controller: TabsController = new TabsController();
1785
1786  @Builder tabBuilder(title: string,targetIndex: number) {
1787    Column(){
1788      Image(this.selectedIndex === targetIndex ? $r('app.media.star_fill') : $r('app.media.star'))
1789        .width(24)
1790        .height(24)
1791        .margin({ bottom: 4 })
1792        .objectFit(ImageFit.Contain)
1793      Text(title).fontColor(this.selectedIndex === targetIndex ? '#1698CE' : '#6B6B6B')
1794    }.width('100%')
1795    .height(50)
1796    .justifyContent(FlexAlign.Center)
1797  }
1798
1799  build() {
1800    Column() {
1801      Tabs({ barPosition: BarPosition.End, index: this.currentIndex, controller: this.controller }) {
1802        TabContent() {
1803          Column(){
1804            Text('Content of the Home tab')
1805          }.width('100%').height('100%').backgroundColor('#00CB87').justifyContent(FlexAlign.Center)
1806        }.tabBar(this.tabBuilder('Home',0))
1807
1808        TabContent() {
1809          Column(){
1810            Text('Content of the Discover tab')
1811          }.width('100%').height('100%').backgroundColor('#007DFF').justifyContent(FlexAlign.Center)
1812        }.tabBar(this.tabBuilder('Discover',1))
1813
1814        TabContent() {
1815          Column(){
1816            Text('Content of the Recommended tab')
1817          }.width('100%').height('100%').backgroundColor('#FFBF00').justifyContent(FlexAlign.Center)
1818        }.tabBar(this.tabBuilder('Recommended',2))
1819
1820        TabContent() {
1821          Column(){
1822            Text('Content of the Me tab')
1823          }.width('100%').height('100%').backgroundColor('#E67C92').justifyContent(FlexAlign.Center)
1824        }.tabBar(this.tabBuilder('Me',3))
1825      }
1826      .vertical(false)
1827      .barMode(BarMode.Fixed)
1828      .barWidth(360)
1829      .barHeight(60)
1830      .animationDuration(0)
1831      .onChange((index: number) => {
1832        this.currentIndex = index;
1833        this.selectedIndex = index;
1834      })
1835      .width(360)
1836      .height(600)
1837      .backgroundColor('#F1F3F5')
1838      .scrollable(true)
1839      .onContentWillChange((currentIndex, comingIndex) => {
1840        if (comingIndex == 2) {
1841          return false;
1842        }
1843        return true;
1844      })
1845
1846      Button('Change Index').width('50%').margin({ top: 20 })
1847        .onClick(()=>{
1848          this.currentIndex = (this.currentIndex + 1) % 4;
1849        })
1850
1851      Button('changeIndex').width('50%').margin({ top: 20 })
1852        .onClick(()=>{
1853          this.currentIndex = (this.currentIndex + 1) % 4;
1854          this.controller.changeIndex(this.currentIndex);
1855        })
1856    }.width('100%')
1857  }
1858}
1859```
1860
1861![tabs9](figures/tabs9.gif)
1862
1863### Example 10: Customizing the Tab Switching Animation
1864
1865This example uses **onChange**, **onAnimationStart**, **onAnimationEnd**, and **onGestureSwipe** APIs to customize the tab switching animation.
1866
1867<!--code_no_check-->
1868
1869```ts
1870// EntryAbility.ets
1871import { Configuration, UIAbility } from '@kit.AbilityKit';
1872import { i18n } from '@kit.LocalizationKit';
1873import { CommonUtil } from '../common/CommonUtil';
1874
1875export default class EntryAbility extends UIAbility {
1876  onConfigurationUpdate(newConfig: Configuration): void {
1877    // Listen for system configuration changes.
1878    if (newConfig.language) {
1879      CommonUtil.setIsRTL(i18n.isRTL(newConfig.language));
1880    }
1881  }
1882}
1883```
1884
1885<!--code_no_check-->
1886
1887```ts
1888// CommonUtil.ets
1889import { i18n, intl } from '@kit.LocalizationKit';
1890
1891export class CommonUtil {
1892  private static isRTL: boolean = i18n.isRTL((new intl.Locale()).language);
1893
1894  public static setIsRTL(isRTL: boolean): void {
1895    CommonUtil.isRTL = isRTL;
1896  }
1897
1898  public static getIsRTL(): boolean {
1899    return CommonUtil.isRTL;
1900  }
1901}
1902```
1903
1904<!--code_no_check-->
1905
1906```ts
1907// xxx.ets
1908import { LengthMetrics } from '@kit.ArkUI';
1909import { CommonUtil } from '../common/CommonUtil';
1910
1911@Entry
1912@Component
1913struct TabsExample {
1914  @State colorArray: [string, string][] =
1915    [['green', '#00CB87'], ['blue', '#007DFF'], ['yellow', '#FFBF00'], ['pink', '#E67C92']];
1916  @State currentIndex: number = 0;
1917  @State animationDuration: number = 300;
1918  @State indicatorLeftMargin: number = 0;
1919  @State indicatorWidth: number = 0;
1920  private tabsWidth: number = 0;
1921  private textInfos: [number, number][] = [];
1922  private isStartAnimateTo: boolean = false;
1923
1924  aboutToAppear():void {
1925    for (let i = 0; i < this.colorArray.length; i++) {
1926      this.textInfos.push([0, 0]);
1927    }
1928  }
1929
1930  @Builder
1931  tabBuilder(index: number, name: string) {
1932    Column() {
1933      Text(name)
1934        .fontSize(16)
1935        .fontColor(this.currentIndex === index ? '#007DFF' : '#182431')
1936        .fontWeight(this.currentIndex === index ? 500 : 400)
1937        .id(index.toString())
1938        .onAreaChange((oldValue: Area, newValue: Area) => {
1939          this.textInfos[index] = [newValue.globalPosition.x as number, newValue.width as number];
1940          if (!this.isStartAnimateTo && this.currentIndex === index && this.tabsWidth > 0) {
1941            this.setIndicatorAttr(this.textInfos[this.currentIndex][0], this.textInfos[this.currentIndex][1]);
1942          }
1943        })
1944    }.width('100%')
1945  }
1946
1947  build() {
1948    Stack({ alignContent: Alignment.TopStart }) {
1949      Tabs({ barPosition: BarPosition.Start }) {
1950        ForEach(this.colorArray, (item: [string, string], index:number) => {
1951          TabContent() {
1952            Column().width('100%').height('100%').backgroundColor(item[1])
1953          }.tabBar(this.tabBuilder(index, item[0]))
1954        })
1955      }
1956      .onAreaChange((oldValue: Area, newValue: Area)=> {
1957        this.tabsWidth = newValue.width as number;
1958        if (!this.isStartAnimateTo) {
1959          this.setIndicatorAttr(this.textInfos[this.currentIndex][0], this.textInfos[this.currentIndex][1]);
1960        }
1961      })
1962      .barWidth('100%')
1963      .barHeight(56)
1964      .width('100%')
1965      .height(296)
1966      .backgroundColor('#F1F3F5')
1967      .animationDuration(this.animationDuration)
1968      .onChange((index: number) => {
1969        this.currentIndex = index; // Listen for index changes to switch between tabs.
1970      })
1971      .onAnimationStart((index: number, targetIndex: number, event: TabsAnimationEvent) => {
1972        // Triggered when the tab switching animation starts. The underline moves with the active tab, along with a width gradient.
1973        this.currentIndex = targetIndex;
1974        this.startAnimateTo(this.animationDuration, this.textInfos[targetIndex][0], this.textInfos[targetIndex][1]);
1975      })
1976      .onAnimationEnd((index: number, event: TabsAnimationEvent) => {
1977        // Triggered when the tab switching animation ends. The underline animation stops.
1978        let currentIndicatorInfo = this.getCurrentIndicatorInfo(index, event);
1979        this.startAnimateTo(0, currentIndicatorInfo.left, currentIndicatorInfo.width);
1980      })
1981      .onGestureSwipe((index: number, event: TabsAnimationEvent) => {
1982        // Triggered on a frame-by-frame basis when the tab is switched by a swipe.
1983        let currentIndicatorInfo = this.getCurrentIndicatorInfo(index, event);
1984        this.currentIndex = currentIndicatorInfo.index;
1985        this.setIndicatorAttr(currentIndicatorInfo.left, currentIndicatorInfo.width);
1986      })
1987
1988      Column()
1989        .height(2)
1990        .width(this.indicatorWidth)
1991        .margin({ start: LengthMetrics.vp(this.indicatorLeftMargin), top: LengthMetrics.vp(48) })
1992        .backgroundColor('#007DFF')
1993    }.width('100%')
1994  }
1995
1996  private getCurrentIndicatorInfo(index: number, event: TabsAnimationEvent): Record<string, number> {
1997    let nextIndex = index;
1998    if (index > 0 && (CommonUtil.getIsRTL() ? event.currentOffset < 0 : event.currentOffset > 0)) {
1999      nextIndex--;
2000    } else if (index < this.textInfos.length - 1 &&
2001        (CommonUtil.getIsRTL() ? event.currentOffset > 0 : event.currentOffset < 0)) {
2002      nextIndex++;
2003    }
2004    let indexInfo = this.textInfos[index];
2005    let nextIndexInfo = this.textInfos[nextIndex];
2006    let swipeRatio = Math.abs(event.currentOffset / this.tabsWidth);
2007    let currentIndex = swipeRatio > 0.5 ? nextIndex : index; // If the swipe is more than halfway, the tab bar switches to the next tab.
2008    let currentLeft = indexInfo[0] + (nextIndexInfo[0] - indexInfo[0]) * swipeRatio;
2009    let currentWidth = indexInfo[1] + (nextIndexInfo[1] - indexInfo[1]) * swipeRatio;
2010    return { 'index': currentIndex, 'left': currentLeft, 'width': currentWidth };
2011  }
2012
2013  private startAnimateTo(duration: number, leftMargin: number, width: number) {
2014    this.isStartAnimateTo = true;
2015    this.getUIContext()?.animateTo({
2016      duration: duration, // Animation duration.
2017      curve: Curve.Linear, // Animation curve.
2018      iterations: 1, // Number of playback times.
2019      playMode: PlayMode.Normal, // Animation playback mode.
2020      onFinish: () => {
2021        this.isStartAnimateTo = false;
2022        console.info('play end');
2023      }
2024    }, () => {
2025      this.setIndicatorAttr(leftMargin, width);
2026    });
2027  }
2028
2029  private setIndicatorAttr(leftMargin: number, width: number) {
2030    this.indicatorWidth = width;
2031    if (CommonUtil.getIsRTL()) {
2032      this.indicatorLeftMargin = this.tabsWidth - leftMargin - width;
2033    } else {
2034      this.indicatorLeftMargin = leftMargin;
2035    }
2036  }
2037}
2038```
2039
2040![tabs10](figures/tabs10.gif)
2041
2042### Example 11: Preloading Child Nodes
2043
2044In this example, the **preloadItems** API is used to preload specified child nodes.
2045
2046```ts
2047// xxx.ets
2048import { BusinessError } from '@kit.BasicServicesKit';
2049
2050@Entry
2051@Component
2052struct TabsPreloadItems {
2053  @State currentIndex: number = 1;
2054  private tabsController: TabsController = new TabsController();
2055
2056  build() {
2057    Column() {
2058      Tabs({ index: this.currentIndex, controller: this.tabsController }) {
2059        TabContent() {
2060          MyComponent({ color: '#00CB87' })
2061        }.tabBar(SubTabBarStyle.of('green'))
2062
2063        TabContent() {
2064          MyComponent({ color: '#007DFF' })
2065        }.tabBar(SubTabBarStyle.of('blue'))
2066
2067        TabContent() {
2068          MyComponent({ color: '#FFBF00' })
2069        }.tabBar(SubTabBarStyle.of('yellow'))
2070
2071        TabContent() {
2072          MyComponent({ color: '#E67C92' })
2073        }.tabBar(SubTabBarStyle.of('pink'))
2074      }
2075      .width(360)
2076      .height(296)
2077      .backgroundColor('#F1F3F5')
2078      .onChange((index: number) => {
2079        this.currentIndex = index;
2080      })
2081
2082      Button('preload items: [0, 2, 3]')
2083        .margin(5)
2084        .onClick(() => {
2085          // Preload child nodes 0, 2, and 3 to improve the performance when users swipe or click to switch to these nodes.
2086          this.tabsController.preloadItems([0, 2, 3])
2087            .then(() => {
2088              console.info('preloadItems success.');
2089            })
2090            .catch((error: BusinessError) => {
2091              console.error('preloadItems failed, error code: ' + error.code + ', error message: ' + error.message);
2092            })
2093        })
2094    }
2095  }
2096}
2097
2098@Component
2099struct MyComponent {
2100  private color: string = '';
2101
2102  aboutToAppear(): void {
2103    console.info('aboutToAppear backgroundColor:' + this.color);
2104  }
2105
2106  aboutToDisappear(): void {
2107    console.info('aboutToDisappear backgroundColor:' + this.color);
2108  }
2109
2110  build() {
2111    Column()
2112      .width('100%')
2113      .height('100%')
2114      .backgroundColor(this.color)
2115  }
2116}
2117```
2118
2119### Example 12: Setting Tab Bar Translation and Opacity
2120
2121This example demonstrates how to set the translation distance and opacity of the tab bar using the **setTabBarTranslate** and **setTabBarOpacity** APIs.
2122
2123```ts
2124// xxx.ets
2125@Entry
2126@Component
2127struct TabsExample {
2128  private controller: TabsController = new TabsController();
2129
2130  build() {
2131    Column() {
2132      Button('Set TabBar Translation Distance').margin({ top: 20 })
2133        .onClick(() => {
2134          this.controller.setTabBarTranslate({ x: -20, y: -20 });
2135        })
2136
2137      Button('Set TabBar Opacity').margin({ top: 20 })
2138        .onClick(() => {
2139          this.controller.setTabBarOpacity(0.5);
2140        })
2141
2142      Tabs({ barPosition: BarPosition.End, controller: this.controller }) {
2143        TabContent() {
2144          Column().width('100%').height('100%').backgroundColor('#00CB87')
2145        }.tabBar(BottomTabBarStyle.of($r('app.media.startIcon'), 'green'))
2146
2147        TabContent() {
2148          Column().width('100%').height('100%').backgroundColor('#007DFF')
2149        }.tabBar(BottomTabBarStyle.of($r('app.media.startIcon'), 'blue'))
2150
2151        TabContent() {
2152          Column().width('100%').height('100%').backgroundColor('#FFBF00')
2153        }.tabBar(BottomTabBarStyle.of($r('app.media.startIcon'), 'yellow'))
2154
2155        TabContent() {
2156          Column().width('100%').height('100%').backgroundColor('#E67C92')
2157        }.tabBar(BottomTabBarStyle.of($r('app.media.startIcon'), 'pink'))
2158      }
2159      .width(360)
2160      .height(296)
2161      .margin({ top: 20 })
2162      .barBackgroundColor('#F1F3F5')
2163    }
2164    .width('100%')
2165  }
2166}
2167```
2168
2169![tabs12](figures/tabBar_translate_opacity.gif)
2170
2171### Example 13: Implementing Lazy Loading and Resource Release of Pages
2172
2173This example demonstrates how to use a custom tab bar with the **Swiper** component and **LazyForEach** to implement lazy loading and resource release of pages.
2174
2175```ts
2176// xxx.ets
2177class MyDataSource implements IDataSource {
2178  private list: number[] = [];
2179
2180  constructor(list: number[]) {
2181    this.list = list;
2182  }
2183
2184  totalCount(): number {
2185    return this.list.length;
2186  }
2187
2188  getData(index: number): number {
2189    return this.list[index];
2190  }
2191
2192  registerDataChangeListener(listener: DataChangeListener): void {
2193  }
2194
2195  unregisterDataChangeListener() {
2196  }
2197}
2198
2199@Entry
2200@Component
2201struct TabsSwiperExample {
2202  @State fontColor: string = '#182431';
2203  @State selectedFontColor: string = '#007DFF';
2204  @State currentIndex: number = 0;
2205  private list: number[] = [];
2206  private tabsController: TabsController = new TabsController();
2207  private swiperController: SwiperController = new SwiperController();
2208  private swiperData: MyDataSource = new MyDataSource([]);
2209
2210  aboutToAppear(): void {
2211    for (let i = 0; i <= 9; i++) {
2212      this.list.push(i);
2213    }
2214    this.swiperData = new MyDataSource(this.list);
2215  }
2216
2217  @Builder tabBuilder(index: number, name: string) {
2218    Column() {
2219      Text(name)
2220        .fontColor(this.currentIndex === index ? this.selectedFontColor : this.fontColor)
2221        .fontSize(16)
2222        .fontWeight(this.currentIndex === index ? 500 : 400)
2223        .lineHeight(22)
2224        .margin({ top: 17, bottom: 7 })
2225      Divider()
2226        .strokeWidth(2)
2227        .color('#007DFF')
2228        .opacity(this.currentIndex === index ? 1 : 0)
2229    }.width('20%')
2230  }
2231
2232  build() {
2233    Column() {
2234      Tabs({ barPosition: BarPosition.Start, controller: this.tabsController }) {
2235        ForEach(this.list, (item: number) => {
2236          TabContent().tabBar(this.tabBuilder(item, 'Tab ' + this.list[item]))
2237        })
2238      }
2239      .onTabBarClick((index: number) => {
2240        this.currentIndex = index;
2241        this.swiperController.changeIndex(index, true);
2242      })
2243      .barMode(BarMode.Scrollable)
2244      .backgroundColor('#F1F3F5')
2245      .height(56)
2246      .width('100%')
2247
2248      Swiper(this.swiperController) {
2249        LazyForEach(this.swiperData, (item: string) => {
2250          Text(item.toString())
2251            .onAppear(()=>{
2252              console.info('onAppear ' + item.toString());
2253            })
2254            .onDisAppear(()=>{
2255              console.info('onDisAppear ' + item.toString());
2256            })
2257            .width('100%')
2258            .height('100%')
2259            .backgroundColor(0xAFEEEE)
2260            .textAlign(TextAlign.Center)
2261            .fontSize(30)
2262        }, (item: string) => item)
2263      }
2264      .loop(false)
2265      .onChange((index: number) => {
2266        this.currentIndex = index;
2267      })
2268      .onAnimationStart((index: number, targetIndex: number, extraInfo: SwiperAnimationEvent) => {
2269        this.currentIndex = targetIndex;
2270        this.tabsController.changeIndex(targetIndex);
2271      })
2272    }
2273  }
2274}
2275```
2276
2277![tabs13](figures/tabs_swiper_lazyForEach.gif)
2278
2279### Example 14: Implementing the Tab Switching Animation
2280
2281This example demonstrates how to implement a tab switching animation by setting **animationMode**.
2282
2283```ts
2284// xxx.ets
2285@Entry
2286@Component
2287struct TabsExample {
2288  @State currentIndex: number = 0;
2289  @State currentAnimationMode: AnimationMode = AnimationMode.CONTENT_FIRST;
2290  private controller: TabsController = new TabsController();
2291  private data: number[] = [];
2292
2293  aboutToAppear(): void {
2294    for (let i = 0; i < 10; i++) {
2295      this.data.push(i);
2296    }
2297  }
2298
2299  @Builder
2300  tabBuilder(title: string,targetIndex: number) {
2301    Column(){
2302      Text(title).fontColor(this.currentIndex === targetIndex ? '#FF0000' : '#6B6B6B')
2303    }.width('100%')
2304    .height(50)
2305    .justifyContent(FlexAlign.Center)
2306  }
2307
2308  build() {
2309    Column() {
2310      Tabs({ barPosition: BarPosition.End, controller: this.controller, index: this.currentIndex }) {
2311        ForEach(this.data, (item: string) => {
2312          TabContent() {
2313            Column(){
2314              Text('' + item)
2315            }.width('100%').height('100%').backgroundColor('#00CB87').justifyContent(FlexAlign.Center)
2316          }.tabBar(this.tabBuilder('P' + item, parseInt(item)))
2317        }, (item: string) => item)
2318      }
2319      .barWidth(360)
2320      .barHeight(60)
2321      .animationMode(this.currentAnimationMode)
2322      .animationDuration(4000)
2323      .onChange((index: number) => {
2324        this.currentIndex = index;
2325      })
2326      .width(360)
2327      .height(120)
2328      .backgroundColor('#F1F3F5')
2329
2330      Text('AnimationMode:' + AnimationMode[this.currentAnimationMode])
2331
2332      Button('AnimationMode').width('50%').margin({ top: 1 }).height(25)
2333        .onClick(()=>{
2334          if (this.currentAnimationMode === AnimationMode.CONTENT_FIRST) {
2335            this.currentAnimationMode = AnimationMode.ACTION_FIRST;
2336          } else if (this.currentAnimationMode === AnimationMode.ACTION_FIRST) {
2337            this.currentAnimationMode = AnimationMode.NO_ANIMATION;
2338          } else if (this.currentAnimationMode === AnimationMode.NO_ANIMATION) {
2339            this.currentAnimationMode = AnimationMode.CONTENT_FIRST_WITH_JUMP;
2340          } else if (this.currentAnimationMode === AnimationMode.CONTENT_FIRST_WITH_JUMP) {
2341            this.currentAnimationMode = AnimationMode.ACTION_FIRST_WITH_JUMP;
2342          } else if (this.currentAnimationMode === AnimationMode.ACTION_FIRST_WITH_JUMP) {
2343            this.currentAnimationMode = AnimationMode.CONTENT_FIRST;
2344          }
2345        })
2346    }.width('100%')
2347  }
2348}
2349```
2350
2351![tabs14](figures/tabs_animationMode.gif)
2352
2353### Example 15: Enabling Tabs to Exceed the Tab Bar Area
2354
2355This example shows how to enable tabs to exceed the tab bar area by setting the **clip** property of the **TabBar** using **barModifier**.
2356
2357```ts
2358// xxx.ets
2359import { CommonModifier } from '@kit.ArkUI';
2360
2361@Entry
2362@Component
2363struct TabsBarModifierExample {
2364  @State selectedIndex: number = 2;
2365  @State currentIndex: number = 2;
2366  @State isClip: boolean = false;
2367  @State tabBarModifier: CommonModifier = new CommonModifier();
2368  private controller: TabsController = new TabsController();
2369
2370  aboutToAppear(): void {
2371    this.tabBarModifier.clip(this.isClip);
2372  }
2373
2374  @Builder
2375  tabBuilder(title: string, targetIndex: number) {
2376    Column() {
2377      Image($r('app.media.startIcon')).width(30).height(30)
2378      Text(title).fontColor(this.selectedIndex === targetIndex ? '#1698CE' : '#6B6B6B')
2379    }.width('100%')
2380    .height(50)
2381    .justifyContent(FlexAlign.Center)
2382    .offset({ y: this.selectedIndex === targetIndex ? -15 : 0 })
2383  }
2384
2385  build() {
2386    Column() {
2387      Tabs({
2388        barPosition: BarPosition.End,
2389        index: this.currentIndex,
2390        controller: this.controller,
2391        barModifier: this.tabBarModifier
2392      }) {
2393        TabContent() {
2394          Column() {
2395            Text('Content of the Home tab')
2396          }.width('100%').height('100%').backgroundColor('#00CB87').justifyContent(FlexAlign.Center)
2397        }.tabBar(this.tabBuilder('Home', 0))
2398
2399        TabContent() {
2400          Column() {
2401            Text('Content of the Discover tab')
2402          }.width('100%').height('100%').backgroundColor('#007DFF').justifyContent(FlexAlign.Center)
2403        }.tabBar(this.tabBuilder('Discover', 1))
2404
2405        TabContent() {
2406          Column() {
2407            Text('Content of the Recommended tab')
2408          }.width('100%').height('100%').backgroundColor('#FFBF00').justifyContent(FlexAlign.Center)
2409        }.tabBar(this.tabBuilder('Recommended', 2))
2410
2411        TabContent() {
2412          Column() {
2413            Text('Content of the Me tab')
2414          }.width('100%').height('100%').backgroundColor('#E67C92').justifyContent(FlexAlign.Center)
2415        }.tabBar(this.tabBuilder('Me',3))
2416      }
2417      .vertical(false)
2418      .barMode(BarMode.Fixed)
2419      .barWidth(340)
2420      .barHeight(60)
2421      .onChange((index: number) => {
2422        this.currentIndex = index;
2423        this.selectedIndex = index;
2424      })
2425      .width(340)
2426      .height(400)
2427      .backgroundColor('#F1F3F5')
2428      .scrollable(true)
2429
2430      Button('isClip: ' + this.isClip)
2431        .margin({ top: 30 })
2432        .onClick(() => {
2433          this.isClip = !this.isClip;
2434          this.tabBarModifier.clip(this.isClip);
2435        })
2436    }.width('100%')
2437  }
2438}
2439```
2440
2441![tabs15](figures/tabs_barModifier_clip.gif)
2442
2443### Example 16: Aligning Tabs
2444
2445This example demonstrates how to align tabs by setting the **align** property of the **TabBar** using **barModifier**.
2446
2447```ts
2448// xxx.ets
2449import { CommonModifier } from '@kit.ArkUI';
2450
2451@Entry
2452@Component
2453struct TabsBarModifierExample {
2454  private controller: TabsController = new TabsController();
2455  @State text: string = 'Text';
2456  @State isVertical: boolean = false;
2457  @State tabBarModifier: CommonModifier = new CommonModifier();
2458
2459  build() {
2460    Column() {
2461      Row() {
2462        Button('Alignment.Start ')
2463          .width('47%')
2464          .height(50)
2465          .margin({ top: 5 })
2466          .onClick((event?: ClickEvent) => {
2467            this.tabBarModifier.align(Alignment.Start);
2468          })
2469          .margin({ right: '6%', bottom: '12vp' })
2470        Button('Alignment.End')
2471          .width('47%')
2472          .height(50)
2473          .margin({ top: 5 })
2474          .onClick((event?: ClickEvent) => {
2475            this.tabBarModifier.align(Alignment.End);
2476          })
2477          .margin({ bottom: '12vp' })
2478      }
2479
2480      Row() {
2481        Button('Alignment.Center')
2482          .width('47%')
2483          .height(50)
2484          .margin({ top: 5 })
2485          .onClick((event?: ClickEvent) => {
2486            this.tabBarModifier.align(Alignment.Center);
2487          })
2488          .margin({ right: '6%', bottom: '12vp' })
2489        Button('isVertical: ' + this.isVertical)
2490          .width('47%')
2491          .height(50)
2492          .margin({ top: 5 })
2493          .onClick((event?: ClickEvent) => {
2494            this.isVertical = !this.isVertical;
2495          })
2496          .margin({ bottom: '12vp' })
2497      }
2498
2499      Row() {
2500        Button('Alignment.Top')
2501          .width('47%')
2502          .height(50)
2503          .margin({ top: 5 })
2504          .onClick((event?: ClickEvent) => {
2505            this.tabBarModifier.align(Alignment.Top);
2506          })
2507          .margin({ right: '6%', bottom: '12vp' })
2508        Button('Alignment.Bottom')
2509          .width('47%')
2510          .height(50)
2511          .margin({ top: 5 })
2512          .onClick((event?: ClickEvent) => {
2513            this.tabBarModifier.align(Alignment.Bottom);
2514          })
2515          .margin({ bottom: '12vp' })
2516      }
2517
2518      Tabs({ barPosition: BarPosition.End, controller: this.controller, barModifier: this.tabBarModifier }) {
2519        TabContent() {
2520          Column().width('100%').height('100%').backgroundColor(Color.Pink)
2521        }.tabBar(SubTabBarStyle.of(this.text))
2522
2523        TabContent() {
2524          Column().width('100%').height('100%').backgroundColor(Color.Green)
2525        }.tabBar(SubTabBarStyle.of(this.text))
2526
2527        TabContent() {
2528          Column().width('100%').height('100%').backgroundColor(Color.Blue)
2529        }.tabBar(SubTabBarStyle.of(this.text))
2530      }
2531      .vertical(this.isVertical)
2532      .height('60%')
2533      .backgroundColor(0xf1f3f5)
2534      .barMode(BarMode.Scrollable)
2535    }
2536    .width('100%')
2537    .height(500)
2538    .margin({ top: 5 })
2539    .padding('24vp')
2540  }
2541}
2542```
2543
2544![tabs16](figures/tabs_barModifier_align.gif)
2545
2546### Example 17: Implementing Synchronized Switching Between the Tabs and TabBar Components
2547
2548This example shows how to implement synchronized switching between the **Tabs** and **TabBar** components using the **onSelected** callback.
2549
2550```ts
2551// xxx.ets
2552@Entry
2553@Component
2554struct TabsExample {
2555  @State fontColor: string = '#182431';
2556  @State selectedFontColor: string = '#007DFF';
2557  @State currentIndex: number = 0;
2558  @State selectedIndex: number = 0;
2559  private controller: TabsController = new TabsController();
2560
2561  @Builder tabBuilder(index: number, name: string) {
2562    Column() {
2563      Text(name)
2564        .fontColor(this.selectedIndex === index ? this.selectedFontColor : this.fontColor)
2565        .fontSize(16)
2566        .fontWeight(this.selectedIndex === index ? 500 : 400)
2567        .lineHeight(22)
2568        .margin({ top: 17, bottom: 7 })
2569      Divider()
2570        .strokeWidth(2)
2571        .color('#007DFF')
2572        .opacity(this.selectedIndex === index ? 1 : 0)
2573    }.width('100%')
2574  }
2575
2576  build() {
2577    Column() {
2578      Tabs({ barPosition: BarPosition.Start, index: this.currentIndex, controller: this.controller }) {
2579        TabContent() {
2580          Column().width('100%').height('100%').backgroundColor('#00CB87')
2581        }.tabBar(this.tabBuilder(0, 'green'))
2582
2583        TabContent() {
2584          Column().width('100%').height('100%').backgroundColor('#007DFF')
2585        }.tabBar(this.tabBuilder(1, 'blue'))
2586
2587        TabContent() {
2588          Column().width('100%').height('100%').backgroundColor('#FFBF00')
2589        }.tabBar(this.tabBuilder(2, 'yellow'))
2590
2591        TabContent() {
2592          Column().width('100%').height('100%').backgroundColor('#E67C92')
2593        }.tabBar(this.tabBuilder(3, 'pink'))
2594      }
2595      .vertical(false)
2596      .barMode(BarMode.Fixed)
2597      .barWidth(360)
2598      .barHeight(56)
2599      .animationDuration(400)
2600      .animationMode(AnimationMode.CONTENT_FIRST)
2601      .onChange((index: number) => {
2602        console.log('onChange index:' + index);
2603        this.currentIndex = index;
2604      })
2605      .onSelected((index: number) => {
2606        console.log('onSelected index:' + index);
2607        this.selectedIndex = index;
2608      })
2609      .onUnselected((index: number) => {
2610        console.log('onUnselected index:' + index);
2611      })
2612      .width('100%')
2613      .height('100%')
2614      .backgroundColor('#F1F3F5')
2615    }.width('100%')
2616  }
2617}
2618```
2619![tabs17](figures/tabs_tarbar.gif)
2620
2621### Example 18: Releasing the Tabs Child components
2622
2623This example demonstrates how to release the **Tabs** child components by setting **cachedMaxCount**.
2624
2625```ts
2626@Entry
2627@Component
2628struct TabsExample {
2629  build() {
2630    Tabs() {
2631      TabContent() {
2632        MyComponent({ color: '#00CB87' })
2633      }.tabBar(SubTabBarStyle.of('green'))
2634
2635      TabContent() {
2636        MyComponent({ color: '#007DFF' })
2637      }.tabBar(SubTabBarStyle.of('blue'))
2638
2639      TabContent() {
2640        MyComponent({ color: '#FFBF00' })
2641      }.tabBar(SubTabBarStyle.of('yellow'))
2642
2643      TabContent() {
2644        MyComponent({ color: '#E67C92' })
2645      }.tabBar(SubTabBarStyle.of('pink'))
2646    }
2647    .width(360)
2648    .height(296)
2649    .backgroundColor('#F1F3F5')
2650    .cachedMaxCount(1, TabsCacheMode.CACHE_BOTH_SIDE)
2651  }
2652}
2653
2654@Component
2655struct MyComponent {
2656  private color: string = '';
2657
2658  aboutToAppear(): void {
2659    console.info('aboutToAppear backgroundColor:' + this.color);
2660  }
2661
2662  aboutToDisappear(): void {
2663    console.info('aboutToDisappear backgroundColor:' + this.color);
2664  }
2665
2666  build() {
2667    Column()
2668      .width('100%')
2669      .height('100%')
2670      .backgroundColor(this.color)
2671  }
2672}
2673```
2674
2675### Example 19: Setting the Tab Bar Background Blur Effect
2676
2677This example shows how to set the background blur effect for the tab bar using **barBackgroundBlurStyle** and **barBackgroundEffect**.
2678
2679```ts
2680// xxx.ets
2681@Entry
2682@Component
2683struct TabsExample {
2684  build() {
2685    Column() {
2686      // Use barBackgroundBlurStyle with an enumerated value to set blur parameters.
2687      Stack() {
2688        Image($r('app.media.startIcon'))
2689        Tabs() {
2690          TabContent() {
2691            Column().width('100%').height('100%').backgroundColor('#00CB87')
2692          }.tabBar('green')
2693
2694          TabContent() {
2695            Column().width('100%').height('100%').backgroundColor('#007DFF')
2696          }.tabBar('blue')
2697
2698          TabContent() {
2699            Column().width('100%').height('100%').backgroundColor('#FFBF00')
2700          }.tabBar('yellow')
2701
2702          TabContent() {
2703            Column().width('100%').height('100%').backgroundColor('#E67C92')
2704          }.tabBar('pink')
2705        }
2706        .barBackgroundBlurStyle(BlurStyle.COMPONENT_THICK,
2707          { colorMode: ThemeColorMode.LIGHT, adaptiveColor: AdaptiveColor.DEFAULT, scale: 1.0 })
2708      }
2709      .width(300)
2710      .height(300)
2711      .margin(10)
2712
2713      // barBackgroundEffect can be used to customize the blur radius, brightness, and saturation of the tabBar.
2714      Stack() {
2715        Image($r('app.media.startIcon'))
2716        Tabs() {
2717          TabContent() {
2718            Column().width('100%').height('100%').backgroundColor('#00CB87')
2719          }.tabBar('green')
2720
2721          TabContent() {
2722            Column().width('100%').height('100%').backgroundColor('#007DFF')
2723          }.tabBar('blue')
2724
2725          TabContent() {
2726            Column().width('100%').height('100%').backgroundColor('#FFBF00')
2727          }.tabBar('yellow')
2728
2729          TabContent() {
2730            Column().width('100%').height('100%').backgroundColor('#E67C92')
2731          }.tabBar('pink')
2732        }
2733        .barBackgroundEffect({ radius: 20, brightness: 0.6, saturation: 15 })
2734      }
2735      .width(300)
2736      .height(300)
2737      .margin(10)
2738    }
2739  }
2740}
2741```
2742![tabs19](figures/tabBar_backgroud.png)
2743
2744### Example 20: Setting the Edge Scrolling Effect
2745
2746This example demonstrates how to implement different edge scrolling effects using **edgeEffect**.
2747
2748```ts
2749// xxx.ets
2750@Entry
2751@Component
2752struct TabsExample {
2753  @State edgeEffect: EdgeEffect = EdgeEffect.Spring;
2754
2755  build() {
2756    Column() {
2757      Tabs() {
2758        TabContent() {
2759          Column().width('100%').height('100%').backgroundColor('#00CB87')
2760        }.tabBar('green')
2761
2762        TabContent() {
2763          Column().width('100%').height('100%').backgroundColor('#007DFF')
2764        }.tabBar('blue')
2765
2766        TabContent() {
2767          Column().width('100%').height('100%').backgroundColor('#FFBF00')
2768        }.tabBar('yellow')
2769
2770        TabContent() {
2771          Column().width('100%').height('100%').backgroundColor('#E67C92')
2772        }.tabBar('pink')
2773      }
2774      .width(360)
2775      .height(296)
2776      .margin({ top: 52 })
2777      .backgroundColor('#F1F3F5')
2778      .edgeEffect(this.edgeEffect)
2779
2780      Button('EdgeEffect.Spring').width('50%').margin({ top: 20 })
2781        .onClick(() => {
2782          this.edgeEffect = EdgeEffect.Spring;
2783        })
2784
2785      Button('EdgeEffect.Fade').width('50%').margin({ top: 20 })
2786        .onClick(() => {
2787          this.edgeEffect = EdgeEffect.Fade;
2788        })
2789
2790      Button('EdgeEffect.None').width('50%').margin({ top: 20 })
2791        .onClick(() => {
2792          this.edgeEffect = EdgeEffect.None;
2793        })
2794    }.width('100%')
2795  }
2796}
2797```
2798![tabs20](figures/tabs_edges_slide.gif)
2799
2800### Example 21: Setting the Tab Switching Animation Curve
2801
2802This example illustrates how to set the tab switching animation curve using the **animationCurve** API, and how to combine it with **animationDuration** to set the animation duration.
2803
2804```ts
2805import { curves } from '@kit.ArkUI';
2806
2807interface TabsItemType { text: string, backgroundColor: ResourceColor }
2808
2809@Entry
2810@Component
2811struct TabsExample {
2812  private tabsController: TabsController = new TabsController();
2813  private curves: (Curve | ICurve) [] = [
2814    curves.interpolatingSpring(-1, 1, 328, 34),
2815    curves.springCurve(10, 1, 228, 30),
2816    curves.cubicBezierCurve(0.25, 0.1, 0.25, 1.0),
2817  ];
2818  @State curveIndex: number = 0;
2819  private datas: TabsItemType[] = [
2820    { text: '1', backgroundColor: '#004AAF' },
2821    { text: '2', backgroundColor: '#2787D9' },
2822    { text: '3', backgroundColor: '#D5D5D5' },
2823    { text: '4', backgroundColor: '#707070' },
2824    { text: '5', backgroundColor: '#F7F7F7' },
2825  ];
2826  @State duration: number = 0;
2827
2828  build() {
2829    Column({ space:2 }) {
2830      Tabs({ controller: this.tabsController }) {
2831        ForEach(this.datas, (item: TabsItemType, index: number) => {
2832          TabContent() {}
2833          .tabBar(item.text)
2834          .backgroundColor(item.backgroundColor)
2835        })
2836      }
2837      .backgroundColor(0xf1f3f5)
2838      .width('100%')
2839      .height(500)
2840      .animationCurve(this.curves[this.curveIndex])
2841      .animationDuration(this.duration)
2842      Row({ space:2 }) {
2843        Text('Curve:' + this.curveIndex)
2844        Button('++').onClick(() => { this.curveIndex = (this.curveIndex + 1) % this.curves.length; })
2845        Button('reset').onClick(() => { this.curveIndex = 0; })
2846      }
2847      .margin({ left: '10vp' })
2848      .width('100%')
2849      Row({ space:2 }) {
2850        Text('Duration:' + this.duration)
2851        Button('+100').onClick(() => { this.duration = (this.duration + 100) % 10000; })
2852        Button('+1000').onClick(() => { this.duration = (this.duration + 1000) % 10000; })
2853        Button('reset').onClick(() => { this.duration = 0; })
2854      }
2855      .margin({ left: '10vp' })
2856      .width('100%')
2857    }
2858    .margin('10vp')
2859  }
2860}
2861```
2862![tabs_curve](figures/tabs_curve.gif)
2863<!--no_check-->