1e41f4b71Sopenharmony_ci# Tabs 2e41f4b71Sopenharmony_ci 3e41f4b71Sopenharmony_ci 4e41f4b71Sopenharmony_ciWhen there is a large amount of page information, to enable the user to focus on the currently displayed content, the page content needs to be classified to improve the page space utilization. The [Tabs](../reference/apis-arkui/arkui-ts/ts-container-tabs.md) component can quickly switch between views on a page, improving information search efficiency and reducing the amount of information that users receive at a time. 5e41f4b71Sopenharmony_ci 6e41f4b71Sopenharmony_ci 7e41f4b71Sopenharmony_ci## Basic Layout 8e41f4b71Sopenharmony_ci 9e41f4b71Sopenharmony_ci The **Tabs** component consists of two parts: **TabContent** and **TabBar**. **TabContent** is the content page, and **TabBar** is the navigation tab bar. The following figure shows the page structure. The layout varies according to the navigation type. In bottom navigation, top navigation, and side navigation, the navigation tab bar is located at the bottom, top, and edge, respectively. 10e41f4b71Sopenharmony_ci **Figure 1** Tabs component layout 11e41f4b71Sopenharmony_ci 12e41f4b71Sopenharmony_ci 13e41f4b71Sopenharmony_ci 14e41f4b71Sopenharmony_ci 15e41f4b71Sopenharmony_ci>**NOTE** 16e41f4b71Sopenharmony_ci> 17e41f4b71Sopenharmony_ci> - The **TabContent** component does not support setting of the common width attribute. By default, its width is the same as that of the parent **Tabs** component. 18e41f4b71Sopenharmony_ci> 19e41f4b71Sopenharmony_ci> - The **TabContent** component does not support setting of the common height attribute. Its height is determined by the height of the parent **Tabs** component and the **TabBar** component. 20e41f4b71Sopenharmony_ci 21e41f4b71Sopenharmony_ci 22e41f4b71Sopenharmony_ci**Tabs** use braces to enclose the tab content, as shown in Figure 2. 23e41f4b71Sopenharmony_ci 24e41f4b71Sopenharmony_ci 25e41f4b71Sopenharmony_ci **Figure 2** Using Tabs and TabContent 26e41f4b71Sopenharmony_ci 27e41f4b71Sopenharmony_ci 28e41f4b71Sopenharmony_ci 29e41f4b71Sopenharmony_ci 30e41f4b71Sopenharmony_ciEach **TabContent** component should be mapped to a tab page, which can be configured through the **tabBar** attribute. The following is an example. 31e41f4b71Sopenharmony_ci 32e41f4b71Sopenharmony_ci```ts 33e41f4b71Sopenharmony_ci TabContent() { 34e41f4b71Sopenharmony_ci Text('Home tab content').fontSize(30) 35e41f4b71Sopenharmony_ci } 36e41f4b71Sopenharmony_ci.tabBar ('Home') 37e41f4b71Sopenharmony_ci``` 38e41f4b71Sopenharmony_ci 39e41f4b71Sopenharmony_ci 40e41f4b71Sopenharmony_ciWhen setting multiple **TabContent** components, place them in sequence in the **Tabs** component. 41e41f4b71Sopenharmony_ci 42e41f4b71Sopenharmony_ci```ts 43e41f4b71Sopenharmony_ciTabs() { 44e41f4b71Sopenharmony_ci TabContent() { 45e41f4b71Sopenharmony_ci Text('Home tab content').fontSize(30) 46e41f4b71Sopenharmony_ci } 47e41f4b71Sopenharmony_ci .tabBar ('Home') 48e41f4b71Sopenharmony_ci 49e41f4b71Sopenharmony_ci TabContent() { 50e41f4b71Sopenharmony_ci Text('Recommended tab content').fontSize(30) 51e41f4b71Sopenharmony_ci } 52e41f4b71Sopenharmony_ci .tabBar ('Recommended') 53e41f4b71Sopenharmony_ci 54e41f4b71Sopenharmony_ci TabContent() { 55e41f4b71Sopenharmony_ci Text ('Discover tab content').fontSize (30) 56e41f4b71Sopenharmony_ci } 57e41f4b71Sopenharmony_ci .tabBar ('Discover') 58e41f4b71Sopenharmony_ci 59e41f4b71Sopenharmony_ci TabContent() { 60e41f4b71Sopenharmony_ci Text ('Me tab content').fontSize (30) 61e41f4b71Sopenharmony_ci } 62e41f4b71Sopenharmony_ci .tabBar ("Me") 63e41f4b71Sopenharmony_ci} 64e41f4b71Sopenharmony_ci``` 65e41f4b71Sopenharmony_ci 66e41f4b71Sopenharmony_ci 67e41f4b71Sopenharmony_ci## Bottom Navigation 68e41f4b71Sopenharmony_ci 69e41f4b71Sopenharmony_ciBottom navigation is the most common navigation mode in applications. The bottom navigation bar is located at the bottom of the level-1 page of the application. It enables the user to quickly have a picture of the feature categories the moment they open the application. In addition, it facilitates one-hand operations of the user. Bottom navigation generally exists as a main navigation form of an application, in that it provides convenient access to primary destinations anywhere in the application. 70e41f4b71Sopenharmony_ci 71e41f4b71Sopenharmony_ci 72e41f4b71Sopenharmony_ci **Figure 3** Bottom navigation bar 73e41f4b71Sopenharmony_ci 74e41f4b71Sopenharmony_ci 75e41f4b71Sopenharmony_ci 76e41f4b71Sopenharmony_ci 77e41f4b71Sopenharmony_ciYou set the position of the navigation bar through the **barPosition** parameter of the **Tabs** component. By default, **barPosition** is set to **BarPosition.Start**, which means that the navigation bar is located on the top. To display the navigation bar at the bottom, set **barPosition** to **BarPosition.End**. 78e41f4b71Sopenharmony_ci 79e41f4b71Sopenharmony_ci 80e41f4b71Sopenharmony_ci```ts 81e41f4b71Sopenharmony_ciTabs({ barPosition: BarPosition.End }) { 82e41f4b71Sopenharmony_ci // TabContent: Home, Discover, Recommended, and Me 83e41f4b71Sopenharmony_ci ... 84e41f4b71Sopenharmony_ci} 85e41f4b71Sopenharmony_ci``` 86e41f4b71Sopenharmony_ci 87e41f4b71Sopenharmony_ci 88e41f4b71Sopenharmony_ci## Top Navigation 89e41f4b71Sopenharmony_ci 90e41f4b71Sopenharmony_ciTop navigation comes in handy when there are many content categories and users need to frequently switch between them. It is usually a further subdivision of the categories in the bottom navigation bar. For example, a theme application may provide a top navigation bar that classifies themes into image, video, and font. 91e41f4b71Sopenharmony_ci 92e41f4b71Sopenharmony_ci **Figure 4** Top navigation bar 93e41f4b71Sopenharmony_ci 94e41f4b71Sopenharmony_ci 95e41f4b71Sopenharmony_ci 96e41f4b71Sopenharmony_ci 97e41f4b71Sopenharmony_ci```ts 98e41f4b71Sopenharmony_ciTabs({ barPosition: BarPosition.Start }) { 99e41f4b71Sopenharmony_ci // TabContent: Following, Video, Game, Digital, Technology, Sports, Movie 100e41f4b71Sopenharmony_ci ... 101e41f4b71Sopenharmony_ci} 102e41f4b71Sopenharmony_ci``` 103e41f4b71Sopenharmony_ci 104e41f4b71Sopenharmony_ci 105e41f4b71Sopenharmony_ci## Side Navigation 106e41f4b71Sopenharmony_ci 107e41f4b71Sopenharmony_ciSide navigation is seldom used in applications. It is more applicable to landscape screens. Because the natural eye movement pattern is from left to right, the side navigation bar is located on the left side by default. 108e41f4b71Sopenharmony_ci 109e41f4b71Sopenharmony_ci 110e41f4b71Sopenharmony_ci **Figure 5** Side navigation bar 111e41f4b71Sopenharmony_ci 112e41f4b71Sopenharmony_ci 113e41f4b71Sopenharmony_ci 114e41f4b71Sopenharmony_ci 115e41f4b71Sopenharmony_ciTo implement the side navigation bar, set the **vertical** attribute of the **Tabs** component to **true**. By default, **vertical** is set to **false**, indicating that the content page and navigation bar are aligned vertically. 116e41f4b71Sopenharmony_ci 117e41f4b71Sopenharmony_ci 118e41f4b71Sopenharmony_ci 119e41f4b71Sopenharmony_ci```ts 120e41f4b71Sopenharmony_ciTabs({ barPosition: BarPosition.Start }) { 121e41f4b71Sopenharmony_ci // TabContent: Home, Discover, Recommended, and Me 122e41f4b71Sopenharmony_ci ... 123e41f4b71Sopenharmony_ci} 124e41f4b71Sopenharmony_ci.vertical(true) 125e41f4b71Sopenharmony_ci.barWidth(100) 126e41f4b71Sopenharmony_ci.barHeight(200) 127e41f4b71Sopenharmony_ci``` 128e41f4b71Sopenharmony_ci 129e41f4b71Sopenharmony_ci 130e41f4b71Sopenharmony_ci>**NOTE** 131e41f4b71Sopenharmony_ci> 132e41f4b71Sopenharmony_ci> - When the **vertical** attribute is set to **false**, the tab bar takes up the whole screen width by default. Set **barWidth** to a proper value. 133e41f4b71Sopenharmony_ci> 134e41f4b71Sopenharmony_ci> - When the **vertical** attribute is set to **true**, the tab bar takes up the actual content height by default. Set **barWidth** to a proper value. 135e41f4b71Sopenharmony_ci 136e41f4b71Sopenharmony_ci 137e41f4b71Sopenharmony_ci## Restricting the Scrolling of the Navigation Bar 138e41f4b71Sopenharmony_ci 139e41f4b71Sopenharmony_ci By default, the navigation bar is scrollable. On some pages that require multi-level classification of content, for example, when both bottom navigation and top navigation are used, the scroll effect of the bottom navigation bar may conflict with that of the top navigation bar. In this case, the scrolling of the bottom navigation bar needs to be restricted to improve user experience. 140e41f4b71Sopenharmony_ci **Figure 6** Restricting the scrolling of the bottom navigation bar 141e41f4b71Sopenharmony_ci 142e41f4b71Sopenharmony_ci 143e41f4b71Sopenharmony_ci 144e41f4b71Sopenharmony_ci 145e41f4b71Sopenharmony_ciThe attribute that enables or disables the scrolling is **scrollable**. Its default value is **true**, indicating that scrolling is enabled. To disable the scrolling, set the attribute to **false**. 146e41f4b71Sopenharmony_ci 147e41f4b71Sopenharmony_ci```ts 148e41f4b71Sopenharmony_ciTabs({ barPosition: BarPosition.End }) { 149e41f4b71Sopenharmony_ci TabContent(){ 150e41f4b71Sopenharmony_ci Column(){ 151e41f4b71Sopenharmony_ci Tabs(){ 152e41f4b71Sopenharmony_ci // Content on the top navigation bar 153e41f4b71Sopenharmony_ci ... 154e41f4b71Sopenharmony_ci } 155e41f4b71Sopenharmony_ci } 156e41f4b71Sopenharmony_ci .backgroundColor('#ff08a8f1') 157e41f4b71Sopenharmony_ci .width('100%') 158e41f4b71Sopenharmony_ci } 159e41f4b71Sopenharmony_ci .tabBar ('Home') 160e41f4b71Sopenharmony_ci 161e41f4b71Sopenharmony_ci // Other TabContent content: Discover, Recommended, and Me 162e41f4b71Sopenharmony_ci ... 163e41f4b71Sopenharmony_ci} 164e41f4b71Sopenharmony_ci.scrollable(false) 165e41f4b71Sopenharmony_ci``` 166e41f4b71Sopenharmony_ci 167e41f4b71Sopenharmony_ci 168e41f4b71Sopenharmony_ci## Fixed Navigation Bar 169e41f4b71Sopenharmony_ci 170e41f4b71Sopenharmony_ciWhen the content categories are relatively fixed and not scalable, a fixed navigation bar can be used. For example, it can be used for the bottom navigation bar, which generally contains 3 to 5 categories. The fixed navigation bar cannot be scrolled or dragged. The tab bar width is evenly distributed among the categories. 171e41f4b71Sopenharmony_ci 172e41f4b71Sopenharmony_ci 173e41f4b71Sopenharmony_ci **Figure 7** Fixed navigation bar 174e41f4b71Sopenharmony_ci 175e41f4b71Sopenharmony_ci 176e41f4b71Sopenharmony_ci 177e41f4b71Sopenharmony_ci 178e41f4b71Sopenharmony_ciTo use a fixed navigation bar, set the **barMode** attribute of the **Tabs** component to **barMode.Fixed** (default). 179e41f4b71Sopenharmony_ci 180e41f4b71Sopenharmony_ci```ts 181e41f4b71Sopenharmony_ciTabs({ barPosition: BarPosition.End }) { 182e41f4b71Sopenharmony_ci // TabContent: Home, Discover, Recommended, and Me 183e41f4b71Sopenharmony_ci ... 184e41f4b71Sopenharmony_ci} 185e41f4b71Sopenharmony_ci.barMode(BarMode.Fixed) 186e41f4b71Sopenharmony_ci``` 187e41f4b71Sopenharmony_ci 188e41f4b71Sopenharmony_ci 189e41f4b71Sopenharmony_ci## Scrollable Navigation Bar 190e41f4b71Sopenharmony_ci 191e41f4b71Sopenharmony_ciThe top navigation bar or side navigation bar can be set to be scrollable if the screen width cannot fully accommodate all the tabs. With a scrollable navigation bar, users can reveal tabs beyond the visible area by touching or swiping on the navigation bar. 192e41f4b71Sopenharmony_ci 193e41f4b71Sopenharmony_ci 194e41f4b71Sopenharmony_ci **Figure 8** Scrollable navigation bar 195e41f4b71Sopenharmony_ci 196e41f4b71Sopenharmony_ci 197e41f4b71Sopenharmony_ci 198e41f4b71Sopenharmony_ci 199e41f4b71Sopenharmony_ciTo use a scrollable navigation bar, set the **barMode** attribute of the **Tabs** component to **BarMode.Scrollable**. 200e41f4b71Sopenharmony_ci 201e41f4b71Sopenharmony_ci```ts 202e41f4b71Sopenharmony_ciTabs({ barPosition: BarPosition.Start }) { 203e41f4b71Sopenharmony_ci // TabContent: follow, video, game, digital, technology, sports, movie, humanities, art, nature, and military 204e41f4b71Sopenharmony_ci ... 205e41f4b71Sopenharmony_ci} 206e41f4b71Sopenharmony_ci.barMode(BarMode.Scrollable) 207e41f4b71Sopenharmony_ci``` 208e41f4b71Sopenharmony_ci 209e41f4b71Sopenharmony_ci 210e41f4b71Sopenharmony_ci## Customizing the Navigation Bar 211e41f4b71Sopenharmony_ci 212e41f4b71Sopenharmony_ciThe bottom navigation bar is generally used on the home page of an application. To deliver a more vibrant experience, you can customize the style of the navigation bar, combining use of text and icons to signify the tab content. 213e41f4b71Sopenharmony_ci 214e41f4b71Sopenharmony_ci 215e41f4b71Sopenharmony_ci **Figure 9** Custom navigation bar 216e41f4b71Sopenharmony_ci 217e41f4b71Sopenharmony_ci 218e41f4b71Sopenharmony_ci 219e41f4b71Sopenharmony_ci 220e41f4b71Sopenharmony_ciBy default, the system uses an underscore (_) to indicate the active tab. For a custom navigation bar, you need to implement the corresponding style to distinguish active tabs from inactive tabs. 221e41f4b71Sopenharmony_ci 222e41f4b71Sopenharmony_ci 223e41f4b71Sopenharmony_ciTo customize the navigation bar, use the **tabBar** parameter and pass in to it custom function component styles in **CustomBuilder** mode. In this example, a custom function component **tabBuilder** is declared, and the input parameters include **title** (tab title), **targetIndex** (target index of the tab), **selectedImg** (image for the selected state), and **normalImg** (image for the unselected state). The UI display style is determined based on whether the value of **currentIndex** (index of the active tab) matches that of **targetIndex** (target index of the tab). 224e41f4b71Sopenharmony_ci 225e41f4b71Sopenharmony_ci```ts 226e41f4b71Sopenharmony_ci@Builder tabBuilder(title: string, targetIndex: number, selectedImg: Resource, normalImg: Resource) { 227e41f4b71Sopenharmony_ci Column() { 228e41f4b71Sopenharmony_ci Image(this.currentIndex === targetIndex ? selectedImg : normalImg) 229e41f4b71Sopenharmony_ci .size({ width: 25, height: 25 }) 230e41f4b71Sopenharmony_ci Text(title) 231e41f4b71Sopenharmony_ci .fontColor(this.currentIndex === targetIndex ? '#1698CE' : '#6B6B6B') 232e41f4b71Sopenharmony_ci } 233e41f4b71Sopenharmony_ci .width('100%') 234e41f4b71Sopenharmony_ci .height(50) 235e41f4b71Sopenharmony_ci .justifyContent(FlexAlign.Center) 236e41f4b71Sopenharmony_ci} 237e41f4b71Sopenharmony_ci``` 238e41f4b71Sopenharmony_ci 239e41f4b71Sopenharmony_ci 240e41f4b71Sopenharmony_ciPass the custom function component to the **tabBar** attribute corresponding to the tab content and transfer the corresponding parameters. 241e41f4b71Sopenharmony_ci 242e41f4b71Sopenharmony_ci```ts 243e41f4b71Sopenharmony_ciTabContent() { 244e41f4b71Sopenharmony_ci Column(){ 245e41f4b71Sopenharmony_ci Text('Me tab content') 246e41f4b71Sopenharmony_ci } 247e41f4b71Sopenharmony_ci .width('100%') 248e41f4b71Sopenharmony_ci .height('100%') 249e41f4b71Sopenharmony_ci .backgroundColor('#007DFF') 250e41f4b71Sopenharmony_ci} 251e41f4b71Sopenharmony_ci.tabBar(this.tabBuilder('Me', 0, $r('app.media.mine_selected'), $r('app.media.mine_normal'))) 252e41f4b71Sopenharmony_ci``` 253e41f4b71Sopenharmony_ci 254e41f4b71Sopenharmony_ci 255e41f4b71Sopenharmony_ci## Switching to a Specified Tab 256e41f4b71Sopenharmony_ci 257e41f4b71Sopenharmony_ciNon-custom navigation bars follow the default switching logic. If you are using a custom navigation bar, you must manually implement the logic for switching tabs so that when the user switches to a tab, the application displays the corresponding tab page. 258e41f4b71Sopenharmony_ci 259e41f4b71Sopenharmony_ci 260e41f4b71Sopenharmony_ci **Figure 10** Content page and tab bar not synced 261e41f4b71Sopenharmony_ci 262e41f4b71Sopenharmony_ci 263e41f4b71Sopenharmony_ci 264e41f4b71Sopenharmony_ciTo sync the content page with the tab bar, use the **onChange** event provided by **Tabs** to listen for changes in the index. Pass the currently active index value to **currentIndex** to enable tab switching. 265e41f4b71Sopenharmony_ci 266e41f4b71Sopenharmony_ci```ts 267e41f4b71Sopenharmony_ci@Entry 268e41f4b71Sopenharmony_ci@Component 269e41f4b71Sopenharmony_cistruct TabsExample1 { 270e41f4b71Sopenharmony_ci @State currentIndex: number = 2 271e41f4b71Sopenharmony_ci 272e41f4b71Sopenharmony_ci @Builder tabBuilder(title: string, targetIndex: number) { 273e41f4b71Sopenharmony_ci Column() { 274e41f4b71Sopenharmony_ci Text(title) 275e41f4b71Sopenharmony_ci .fontColor(this.currentIndex === targetIndex ? '#1698CE' : '#6B6B6B') 276e41f4b71Sopenharmony_ci } 277e41f4b71Sopenharmony_ci } 278e41f4b71Sopenharmony_ci 279e41f4b71Sopenharmony_ci build() { 280e41f4b71Sopenharmony_ci Column() { 281e41f4b71Sopenharmony_ci Tabs({ barPosition: BarPosition.End }) { 282e41f4b71Sopenharmony_ci TabContent() { 283e41f4b71Sopenharmony_ci ... 284e41f4b71Sopenharmony_ci }.tabBar(this.tabBuilder('Home', 0)) 285e41f4b71Sopenharmony_ci 286e41f4b71Sopenharmony_ci TabContent() { 287e41f4b71Sopenharmony_ci ... 288e41f4b71Sopenharmony_ci }.tabBar(this.tabBuilder('Discover', 1)) 289e41f4b71Sopenharmony_ci 290e41f4b71Sopenharmony_ci TabContent() { 291e41f4b71Sopenharmony_ci ... 292e41f4b71Sopenharmony_ci }.tabBar(this.tabBuilder('Recommended', 2)) 293e41f4b71Sopenharmony_ci 294e41f4b71Sopenharmony_ci TabContent() { 295e41f4b71Sopenharmony_ci ... 296e41f4b71Sopenharmony_ci }.tabBar(this.tabBuilder('Me',3)) 297e41f4b71Sopenharmony_ci } 298e41f4b71Sopenharmony_ci .animationDuration(0) 299e41f4b71Sopenharmony_ci .backgroundColor('#F1F3F5') 300e41f4b71Sopenharmony_ci .onChange((index: number) => { 301e41f4b71Sopenharmony_ci this.currentIndex = index 302e41f4b71Sopenharmony_ci }) 303e41f4b71Sopenharmony_ci }.width('100%') 304e41f4b71Sopenharmony_ci } 305e41f4b71Sopenharmony_ci} 306e41f4b71Sopenharmony_ci``` 307e41f4b71Sopenharmony_ci **Figure 10** Content page and tab bar synced 308e41f4b71Sopenharmony_ci 309e41f4b71Sopenharmony_ci 310e41f4b71Sopenharmony_ci 311e41f4b71Sopenharmony_ciTo enable switching between content pages and tabs without swiping, you can pass **currentIndex** to the **index** parameter of **Tabs**. By changing the value of **currentIndex**, you can navigate to the content page corresponding to a specific index. Alternatively, use **TabsController**, which is the controller for the **Tabs** component, to manage content page switches. By using the **changeIndex** API of **TabsController**, you can set your application to display the tab content corresponding to the specified index. 312e41f4b71Sopenharmony_ci```ts 313e41f4b71Sopenharmony_ci@State currentIndex: number = 2 314e41f4b71Sopenharmony_ciprivate controller: TabsController = new TabsController() 315e41f4b71Sopenharmony_ci 316e41f4b71Sopenharmony_ciTabs({ barPosition: BarPosition.End, index: this.currentIndex, controller: this.controller }) { 317e41f4b71Sopenharmony_ci ... 318e41f4b71Sopenharmony_ci} 319e41f4b71Sopenharmony_ci.height(600) 320e41f4b71Sopenharmony_ci.onChange((index: number) => { 321e41f4b71Sopenharmony_ci this.currentIndex = index 322e41f4b71Sopenharmony_ci}) 323e41f4b71Sopenharmony_ci 324e41f4b71Sopenharmony_ciButton('Switch Tab by Index').width('50%').margin({ top: 20 }) 325e41f4b71Sopenharmony_ci .onClick(()=>{ 326e41f4b71Sopenharmony_ci this.currentIndex = (this.currentIndex + 1) % 4 327e41f4b71Sopenharmony_ci}) 328e41f4b71Sopenharmony_ci 329e41f4b71Sopenharmony_ciButton('changeIndex').width('50%').margin({ top: 20 }) 330e41f4b71Sopenharmony_ci .onClick(()=>{ 331e41f4b71Sopenharmony_ci let index = (this.currentIndex + 1) % 4 332e41f4b71Sopenharmony_ci this.controller.changeIndex(index) 333e41f4b71Sopenharmony_ci}) 334e41f4b71Sopenharmony_ci``` 335e41f4b71Sopenharmony_ci 336e41f4b71Sopenharmony_ci **Figure 12** Switching to a specific tab page 337e41f4b71Sopenharmony_ci 338e41f4b71Sopenharmony_ci 339e41f4b71Sopenharmony_ci 340e41f4b71Sopenharmony_ciYou can use the **onContentWillChange** API of the **Tabs** component to customize the interception callback function. The interception callback function is called when a new page is about to be displayed. If the callback returns **true**, the tab can switch to the new page. If the callback returns **false**, the tab cannot switch to the new page and will remain on the current page. 341e41f4b71Sopenharmony_ci 342e41f4b71Sopenharmony_ci```ts 343e41f4b71Sopenharmony_ciTabs({ barPosition: BarPosition.End, controller: this.controller, index: this.currentIndex }) {...} 344e41f4b71Sopenharmony_ci.onContentWillChange((currentIndex, comingIndex) => { 345e41f4b71Sopenharmony_ci if (comingIndex == 2) { 346e41f4b71Sopenharmony_ci return false 347e41f4b71Sopenharmony_ci } 348e41f4b71Sopenharmony_ci return true 349e41f4b71Sopenharmony_ci}) 350e41f4b71Sopenharmony_ci``` 351e41f4b71Sopenharmony_ci **Figure 13** Customizing the page switching interception event 352e41f4b71Sopenharmony_ci 353e41f4b71Sopenharmony_ci 354e41f4b71Sopenharmony_ci<!--Del--> 355e41f4b71Sopenharmony_ci## Supporting Aging-Friendly Design 356e41f4b71Sopenharmony_ci 357e41f4b71Sopenharmony_ciIn ging-friendly scenarios with large font sizes, the bottom tab bar offers a dialog box with large fonts for content display. When the component detects a large font setting, it constructs a long-press dialog box based on the configured text and icons. After the user long-presses the tab bar and then swipes in the dialog box to switch to the next tab, the dialog box updates with content of the new tab. Upon releasing, the dialog box closes and the UI switches to the corresponding tab page. 358e41f4b71Sopenharmony_ci 359e41f4b71Sopenharmony_ci> **NOTE** 360e41f4b71Sopenharmony_ci> 361e41f4b71Sopenharmony_ci> The dialog box applies only to bottom tab bars, that is, tab bars in the style of **BottomTabBarStyle**. 362e41f4b71Sopenharmony_ci 363e41f4b71Sopenharmony_ci**Figure 14** Displaying an aging-friendly dialog box by long-pressing the bottom tab bar in an aging-friendly scenario 364e41f4b71Sopenharmony_ci 365e41f4b71Sopenharmony_ci 366e41f4b71Sopenharmony_ci 367e41f4b71Sopenharmony_ci```ts 368e41f4b71Sopenharmony_ciimport { abilityManager, Configuration } from '@kit.AbilityKit'; 369e41f4b71Sopenharmony_ciimport { BusinessError } from '@kit.BasicServicesKit'; 370e41f4b71Sopenharmony_ciimport { promptAction, uiAppearance } from '@kit.ArkUI'; 371e41f4b71Sopenharmony_ci 372e41f4b71Sopenharmony_ci@Entry 373e41f4b71Sopenharmony_ci@Component 374e41f4b71Sopenharmony_cistruct Demo { 375e41f4b71Sopenharmony_ci @State fontColor: string = '#182431'; 376e41f4b71Sopenharmony_ci @State selectedFontColor: string = '#007DFF'; 377e41f4b71Sopenharmony_ci @State currentIndex: number = 0; 378e41f4b71Sopenharmony_ci @State currentFontSizeScale: string = ''; 379e41f4b71Sopenharmony_ci @State showBuilderTab: boolean = false; 380e41f4b71Sopenharmony_ci @State fontSize: number = 15; 381e41f4b71Sopenharmony_ci private darkModeKey: string[] = Object.keys(uiAppearance.DarkMode).filter( 382e41f4b71Sopenharmony_ci key => typeof uiAppearance.DarkMode[key] === 'number') 383e41f4b71Sopenharmony_ci 384e41f4b71Sopenharmony_ci async setFontScale(scale: number): Promise<void> { 385e41f4b71Sopenharmony_ci let configInit: Configuration = { 386e41f4b71Sopenharmony_ci fontSizeScale: scale, 387e41f4b71Sopenharmony_ci }; 388e41f4b71Sopenharmony_ci abilityManager.updateConfiguration(configInit, (err: BusinessError) => { 389e41f4b71Sopenharmony_ci if (err) { 390e41f4b71Sopenharmony_ci console.error(`updateConfiguration fail, err: ${JSON.stringify(err)}`); 391e41f4b71Sopenharmony_ci promptAction.showToast({ message: `scale:${scale}, err:${JSON.stringify(err)}` }) 392e41f4b71Sopenharmony_ci } else { 393e41f4b71Sopenharmony_ci this.currentFontSizeScale = String(scale); 394e41f4b71Sopenharmony_ci if (scale > 1) { 395e41f4b71Sopenharmony_ci this.fontSize = 8; 396e41f4b71Sopenharmony_ci } else { 397e41f4b71Sopenharmony_ci this.fontSize = 15; 398e41f4b71Sopenharmony_ci } 399e41f4b71Sopenharmony_ci console.log('updateConfiguration success.'); 400e41f4b71Sopenharmony_ci promptAction.showToast({ message: `scale:${scale}, updateConfiguration success.` }) 401e41f4b71Sopenharmony_ci } 402e41f4b71Sopenharmony_ci }); 403e41f4b71Sopenharmony_ci } 404e41f4b71Sopenharmony_ci 405e41f4b71Sopenharmony_ci darkMode(isDarkMode: boolean): void { 406e41f4b71Sopenharmony_ci let mode: uiAppearance.DarkMode = uiAppearance.DarkMode.ALWAYS_LIGHT; 407e41f4b71Sopenharmony_ci if (isDarkMode) { 408e41f4b71Sopenharmony_ci mode = uiAppearance.DarkMode.ALWAYS_DARK; 409e41f4b71Sopenharmony_ci } 410e41f4b71Sopenharmony_ci if (mode == uiAppearance.getDarkMode()) { 411e41f4b71Sopenharmony_ci console.info(`TitleDarkMode Set ${this.darkModeKey[mode]} successfully.`) 412e41f4b71Sopenharmony_ci return; 413e41f4b71Sopenharmony_ci } 414e41f4b71Sopenharmony_ci try { 415e41f4b71Sopenharmony_ci uiAppearance.setDarkMode(mode).then(() => { 416e41f4b71Sopenharmony_ci console.info(`TitleDarkMode Set ${this.darkModeKey[mode]} successfully.`) 417e41f4b71Sopenharmony_ci }).catch((error: Error) => { 418e41f4b71Sopenharmony_ci console.error(`TitleDarkMode Set ${this.darkModeKey[mode]} failed, ${error.message}`); 419e41f4b71Sopenharmony_ci }); 420e41f4b71Sopenharmony_ci } catch (error) { 421e41f4b71Sopenharmony_ci let message = (error as BusinessError).message; 422e41f4b71Sopenharmony_ci console.error(`TitleDarkMode Set dark-mode failed, ${message}`); 423e41f4b71Sopenharmony_ci } 424e41f4b71Sopenharmony_ci } 425e41f4b71Sopenharmony_ci 426e41f4b71Sopenharmony_ci build() { 427e41f4b71Sopenharmony_ci Column() { 428e41f4b71Sopenharmony_ci Column() { 429e41f4b71Sopenharmony_ci Row() { 430e41f4b71Sopenharmony_ci Text(`current fontSizeScale:${this.currentFontSizeScale}`) 431e41f4b71Sopenharmony_ci .margin({ top: 5, bottom: 5 }) 432e41f4b71Sopenharmony_ci .fontSize(this.fontSize) 433e41f4b71Sopenharmony_ci } 434e41f4b71Sopenharmony_ci 435e41f4b71Sopenharmony_ci Row() { 436e41f4b71Sopenharmony_ci Button('1.75') 437e41f4b71Sopenharmony_ci .margin({ top: 5, bottom: 5 }) 438e41f4b71Sopenharmony_ci .fontSize(this.fontSize) 439e41f4b71Sopenharmony_ci .width('40%') 440e41f4b71Sopenharmony_ci .onClick(async () => { 441e41f4b71Sopenharmony_ci await this.setFontScale(1.75); 442e41f4b71Sopenharmony_ci }) 443e41f4b71Sopenharmony_ci Button('2') 444e41f4b71Sopenharmony_ci .margin({ top: 5, bottom: 5 }) 445e41f4b71Sopenharmony_ci .fontSize(this.fontSize) 446e41f4b71Sopenharmony_ci .width('40%') 447e41f4b71Sopenharmony_ci .onClick(async () => { 448e41f4b71Sopenharmony_ci await this.setFontScale(2); 449e41f4b71Sopenharmony_ci }) 450e41f4b71Sopenharmony_ci }.margin({ top: 25 }) 451e41f4b71Sopenharmony_ci 452e41f4b71Sopenharmony_ci Row() { 453e41f4b71Sopenharmony_ci Button('3.2') 454e41f4b71Sopenharmony_ci .margin({ top: 5, bottom: 5 }) 455e41f4b71Sopenharmony_ci .fontSize(this.fontSize) 456e41f4b71Sopenharmony_ci .width('40%') 457e41f4b71Sopenharmony_ci .onClick(async () => { 458e41f4b71Sopenharmony_ci await this.setFontScale(3.2); 459e41f4b71Sopenharmony_ci }) 460e41f4b71Sopenharmony_ci Button('1') 461e41f4b71Sopenharmony_ci .margin({ top: 5, bottom: 5 }) 462e41f4b71Sopenharmony_ci .fontSize(this.fontSize) 463e41f4b71Sopenharmony_ci .width('40%') 464e41f4b71Sopenharmony_ci .onClick(async () => { 465e41f4b71Sopenharmony_ci await this.setFontScale(1); 466e41f4b71Sopenharmony_ci }) 467e41f4b71Sopenharmony_ci } 468e41f4b71Sopenharmony_ci 469e41f4b71Sopenharmony_ci Row() { 470e41f4b71Sopenharmony_ci Button('Dark Mode') 471e41f4b71Sopenharmony_ci .margin({ top: 5, bottom: 5 }) 472e41f4b71Sopenharmony_ci .fontSize(this.fontSize) 473e41f4b71Sopenharmony_ci .width('40%') 474e41f4b71Sopenharmony_ci .onClick(async () => { 475e41f4b71Sopenharmony_ci this.darkMode(true); 476e41f4b71Sopenharmony_ci }) 477e41f4b71Sopenharmony_ci Button('Light Mode') 478e41f4b71Sopenharmony_ci .margin({ top: 5, bottom: 5 }) 479e41f4b71Sopenharmony_ci .fontSize(this.fontSize) 480e41f4b71Sopenharmony_ci .width('40%') 481e41f4b71Sopenharmony_ci .onClick(async () => { 482e41f4b71Sopenharmony_ci this.darkMode(false); 483e41f4b71Sopenharmony_ci }) 484e41f4b71Sopenharmony_ci } 485e41f4b71Sopenharmony_ci }.alignItems(HorizontalAlign.Start) 486e41f4b71Sopenharmony_ci 487e41f4b71Sopenharmony_ci Column() { 488e41f4b71Sopenharmony_ci Tabs({ barPosition: BarPosition.End }) { 489e41f4b71Sopenharmony_ci TabContent() { 490e41f4b71Sopenharmony_ci Column().width('100%').height('100%').backgroundColor(Color.Pink) 491e41f4b71Sopenharmony_ci }.tabBar(new BottomTabBarStyle($r('sys.media.ohos_app_icon'), 'OverLength')) 492e41f4b71Sopenharmony_ci TabContent() { 493e41f4b71Sopenharmony_ci Column().width('100%').height('100%').backgroundColor(Color.Yellow) 494e41f4b71Sopenharmony_ci }.tabBar(new BottomTabBarStyle($r('sys.media.ohos_app_icon'), 'SixLine')) 495e41f4b71Sopenharmony_ci TabContent() { 496e41f4b71Sopenharmony_ci Column().width('100%').height('100%').backgroundColor(Color.Blue) 497e41f4b71Sopenharmony_ci }.tabBar(new BottomTabBarStyle($r('sys.media.ohos_app_icon'), 'Blue')) 498e41f4b71Sopenharmony_ci TabContent() { 499e41f4b71Sopenharmony_ci Column().width('100%').height('100%').backgroundColor(Color.Green) 500e41f4b71Sopenharmony_ci }.tabBar(new BottomTabBarStyle($r('sys.media.ohos_app_icon'), 'Green')) 501e41f4b71Sopenharmony_ci } 502e41f4b71Sopenharmony_ci .vertical(false) 503e41f4b71Sopenharmony_ci .scrollable(true) 504e41f4b71Sopenharmony_ci .barMode(BarMode.Fixed) 505e41f4b71Sopenharmony_ci .onChange((index: number) => { 506e41f4b71Sopenharmony_ci console.info(index.toString()) 507e41f4b71Sopenharmony_ci }) 508e41f4b71Sopenharmony_ci .width('100%') 509e41f4b71Sopenharmony_ci .backgroundColor(0xF1F3F5) 510e41f4b71Sopenharmony_ci }.width('80%').height(200) 511e41f4b71Sopenharmony_ci .margin({ top: 200 }) 512e41f4b71Sopenharmony_ci }.width('100%') 513e41f4b71Sopenharmony_ci } 514e41f4b71Sopenharmony_ci} 515e41f4b71Sopenharmony_ci``` 516e41f4b71Sopenharmony_ci<!--DelEnd-->