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