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<EdgeEffect>) 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<[EdgeEffect](ts-appendix-enums.md#edgeeffect)> | 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 2863<!--no_check-->