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![tabs-layout](figures/tabs-layout.png)
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![tabs-tabscontent](figures/tabs-tabscontent.png)
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![bottom-navigation](figures/bottom-navigation.gif)
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![top-navigation](figures/top-navigation.gif)
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![side-navigation](figures/side-navigation.png)
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![restricted-navigation](figures/restricted-navigation.gif)
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![fixed-navigation](figures/fixed-navigation.gif)
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![scrollable-navigation](figures/scrollable-navigation.gif)
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![custom-navigation-bar](figures/custom-navigation-bar.png)
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![Content Page and Tab Bar Not Synced](figures/tabcontent_tabbar_not_sync.gif)
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![Content Page and Tab Bar Synced](figures/tabcontent_tabbar_sync.gif)
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![Switching to a Specified Tab Page](figures/TabsChange.gif)
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![TabsChange3](figures/TabsChange3.gif)
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![Aging-Friendly Design](figures/tabs11.png)
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-->