1# Tabs
2
3通过页签进行内容视图切换的容器组件,每个页签对应一个内容视图。
4
5>  **说明:**
6>
7>  该组件从API Version 7开始支持。后续版本如有新增内容,则采用上角标单独标记该内容的起始版本。
8>
9>  该组件从API Version 11开始默认支持安全区避让特性(默认值为:expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.BOTTOM])),开发者可以重写该属性覆盖默认行为,API Version 11之前的版本需配合[expandSafeArea](ts-universal-attributes-expand-safe-area.md)属性实现安全区避让。
10
11
12## 子组件
13
14不支持自定义组件作为子组件, 仅可包含子组件[TabContent](ts-container-tabcontent.md), 以及渲染控制类型[if/else](../../../quick-start/arkts-rendering-control-ifelse.md)和[ForEach](../../../quick-start/arkts-rendering-control-foreach.md), 并且if/else和ForEach下也仅支持TabContent, 不支持自定义组件。
15
16>  **说明:**
17>
18>  Tabs子组件的visibility属性设置为None,或者visibility属性设置为Hidden时,对应子组件不显示,但依然会在视窗内占位。
19>
20>  Tabs子组件TabContent显示之后不会销毁,若需要页面懒加载和释放,可以参考[示例12](#示例12页面懒加载和释放)。
21
22
23## 接口
24
25Tabs(value?: {barPosition?: BarPosition, index?: number, controller?: TabsController})
26
27**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
28
29**系统能力:** SystemCapability.ArkUI.ArkUI.Full
30
31**参数:**
32
33| 参数名         | 类型                              | 必填   | 说明                                     |
34| ----------- | --------------------------------- | ---- | ---------------------------------------- |
35| barPosition | [BarPosition](#barposition枚举说明)| 否    | 设置Tabs的页签位置。<br/>默认值:BarPosition.Start   |
36| index       | number                            | 否    | 设置当前显示页签的索引。<br/>默认值:0<br/>**说明:** <br/>设置为小于0的值时按默认值显示。<br/>可选值为[0, TabContent子节点数量-1]。<br/>直接修改index跳页时,切换动效不生效。 使用TabController的changeIndex时,默认生效切换动效,可以设置animationDuration为0关闭动画。<br />从API version 10开始,该参数支持[$$](../../../quick-start/arkts-two-way-sync.md)双向绑定变量。<br/>Tabs重建、系统资源切换(如系统字体切换、系统深浅色切换)或者组件属性变化时,会跳转到index对应的页面。若需要在上述情况下不跳转,建议使用双向绑定。 |
37| controller  | [TabsController](#tabscontroller) | 否    | 设置Tabs控制器。                               |
38
39## BarPosition枚举说明
40
41Tabs页签位置枚举。
42
43**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
44
45**系统能力:** SystemCapability.ArkUI.ArkUI.Full
46
47| 名称  | 说明                                                         |
48| ----- | ------------------------------------------------------------ |
49| Start | vertical属性方法设置为true时,页签位于容器左侧;vertical属性方法设置为false时,页签位于容器顶部。 |
50| End   | vertical属性方法设置为true时,页签位于容器右侧;vertical属性方法设置为false时,页签位于容器底部。 |
51
52
53## 属性
54
55除支持[通用属性](ts-universal-attributes-size.md)外,还支持以下属性:
56
57### vertical
58
59vertical(value: boolean)
60
61设置是否为纵向Tab。
62
63**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
64
65**系统能力:** SystemCapability.ArkUI.ArkUI.Full
66
67**参数:**
68
69| 参数名 | 类型    | 必填 | 说明                                                         |
70| ------ | ------- | ---- | ------------------------------------------------------------ |
71| value  | boolean | 是   | 是否为纵向Tab。<br/>默认值:false,横向Tabs,为true时纵向Tabs。<br/>当横向Tabs设置height为auto时,Tabs组件高度自适应子组件高度,即为tabBar高度+divider线宽+TabContent高度+上下padding值+上下border宽度。<br/>当纵向Tabs设置width为auto时,Tabs组件宽度自适应子组件宽度,即为tabBar宽度+divider线宽+TabContent宽度+左右padding值+左右border宽度。<br/>尽量保持每一个页面中的子组件尺寸大小一致,避免滑动页面时出现页面切换动画跳动现象。 |
72
73### scrollable
74
75scrollable(value: boolean)
76
77设置是否可以通过滑动页面进行页面切换。
78
79**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
80
81**系统能力:** SystemCapability.ArkUI.ArkUI.Full
82
83**参数:**
84
85| 参数名 | 类型    | 必填 | 说明                                                         |
86| ------ | ------- | ---- | ------------------------------------------------------------ |
87| value  | boolean | 是   | 是否可以通过滑动页面进行页面切换。<br/>默认值:true,可以通过滑动页面进行页面切换。为false时不可滑动切换页面。 |
88
89### barMode
90
91barMode(value: BarMode, options?: ScrollableBarModeOptions)
92
93设置TabBar布局模式。
94
95**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
96
97**系统能力:** SystemCapability.ArkUI.ArkUI.Full
98
99**参数:**
100
101| 参数名                | 类型                                                         | 必填 | 说明                                                         |
102| --------------------- | ------------------------------------------------------------ | ---- | ------------------------------------------------------------ |
103| value                 | [BarMode](#barmode枚举说明)                                  | 是   | 布局模式。<br/>默认值:BarMode.Fixed                                                 |
104| options<sup>10+</sup> | [ScrollableBarModeOptions](#scrollablebarmodeoptions10对象说明) | 否   | Scrollable模式下的TabBar的布局样式。<br/>**说明:** <br/>仅Scrollable且水平模式下有效。 |
105
106### barMode<sup>10+</sup>
107
108barMode(value: BarMode.Fixed)
109
110设置TabBar布局模式为BarMode.Fixed111
112**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
113
114**系统能力:** SystemCapability.ArkUI.ArkUI.Full
115
116**参数:**
117
118| 参数名    | 类型                             | 必填 | 说明                                    |
119| -------- | -------------------------------- | ---- | ------------------------------------ |
120| value    | [BarMode.Fixed](#barmode枚举说明) | 是   | 所有TabBar会平均分配barWidth宽度(纵向时平均分配barHeight高度)。   |
121
122### barMode<sup>10+</sup>
123
124barMode(value: BarMode.Scrollable, options: ScrollableBarModeOptions)
125
126设置TabBar布局模式为BarMode.Scrollable127
128**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
129
130**系统能力:** SystemCapability.ArkUI.ArkUI.Full
131
132**参数:**
133
134| 参数名    | 类型                              | 必填 | 说明                                    |
135| -------- | --------------------------------- | ---- | ------------------------------------- |
136| value    | [BarMode.Scrollable](#barmode枚举说明) | 是   | 所有TabBar都使用实际布局宽度,超过总宽度(横向Tabs的barWidth,纵向Tabs的barHeight)后可滑动。        |
137| options | [ScrollableBarModeOptions](#scrollablebarmodeoptions10对象说明) | 是   | Scrollable模式下的TabBar的布局样式。<br/>**说明:** <br/>仅水平模式下有效。  |
138
139### barWidth
140
141barWidth(value: Length)
142
143设置TabBar的宽度值。设置为小于0或大于Tabs宽度值时,按默认值显示。
144
145**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
146
147**系统能力:** SystemCapability.ArkUI.ArkUI.Full
148
149**参数:**
150
151| 参数名 | 类型                                      | 必填 | 说明                                                         |
152| ------ | ----------------------------------------- | ---- | ------------------------------------------------------------ |
153| value  | [Length](ts-types.md#length)<sup>8+</sup> | 是   | TabBar的宽度值。<br/>默认值:<br/>未设置[SubTabBarStyle](ts-container-tabcontent.md#subtabbarstyle9)和[BottomTabBarStyle](ts-container-tabcontent.md#bottomtabbarstyle9)的TabBar且vertical属性为false时,默认值为Tabs的宽度。<br/>未设置SubTabBarStyle和BottomTabBarStyle的TabBar且vertical属性为true时,默认值为56vp。<br/>设置SubTabBarStyle样式且vertical属性为false时,默认值为Tabs的宽度。<br/>设置SubTabBarStyle样式且vertical属性为true时,默认值为56vp。<br/>设置BottomTabBarStyle样式且vertical属性为true时,默认值为96vp。<br/>设置BottomTabBarStyle样式且vertical属性为false时,默认值为Tabs的宽度。 |
154
155### barHeight
156
157barHeight(value: Length)
158
159设置TabBar的高度值。设置为'auto'时,TabBar自适应子组件高度,仅在水平模式下有效。设置为小于0或大于Tabs高度值时,按默认值显示。
160
161API Version 14之前的版本,若设置barHeight为固定值后,TabBar无法扩展底部安全区。从API Version 14开始支持配合[safeAreaPadding](./ts-universal-attributes-size.md#safeareapadding14)属性,当safeAreaPadding不设置bottom或者bottom设置为0时,可以实现扩展安全区。
162
163**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
164
165**系统能力:** SystemCapability.ArkUI.ArkUI.Full
166
167**参数:**
168
169| 参数名 | 类型                                      | 必填 | 说明                                                         |
170| ------ | ----------------------------------------- | ---- | ------------------------------------------------------------ |
171| value  | [Length](ts-types.md#length)<sup>8+</sup> | 是   | TabBar的高度值。<br/>默认值:<br/>未设置带样式的TabBar且vertical属性为false时,默认值为56vp。<br/>未设置带样式的TabBar且vertical属性为true时,默认值为Tabs的高度。<br/>设置[SubTabBarStyle](ts-container-tabcontent.md#subtabbarstyle9)样式且vertical属性为false时,默认值为56vp。<br/>设置SubTabBarStyle样式且vertical属性为true时,默认值为Tabs的高度。<br/>设置[BottomTabBarStyle](ts-container-tabcontent.md#bottomtabbarstyle9)样式且vertical属性为true时,默认值为Tabs的高度。<br/>设置BottomTabBarStyle样式且vertical属性为false时,默认值为56vp, 从API Version 12开始,默认值变更为48vp。 |
172
173### animationDuration
174
175animationDuration(value: number)
176
177设置点击TabBar页签和调用TabsController的changeIndex接口切换TabContent的动画时长。该参数不支持百分比设置。
178
179**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
180
181**系统能力:** SystemCapability.ArkUI.ArkUI.Full
182
183**参数:**
184
185| 参数名 | 类型   | 必填 | 说明                                                         |
186| ------ | ------ | ---- | ------------------------------------------------------------ |
187| value  | number | 是   | 点击TabBar页签和调用TabsController的changeIndex接口切换TabContent的动画时长。<br/>默认值:<br/>API version 10及以前,不设置该属性或设置为null时,默认值为0,即点击TabBar页签和调用TabsController的changeIndex接口切换TabContent无动画。设置为小于0或undefined时,默认值为300。<br/>API version 11及以后,不设置该属性或设置为异常值,且设置TabBar为BottomTabBarStyle样式时,默认值为0。设置TabBar为其他样式时,默认值为300。<br/>单位:ms |
188
189### animationMode<sup>12+</sup>
190
191animationMode(mode: Optional\<AnimationMode\>)
192
193设置点击TabBar页签时切换TabContent的动画形式。
194
195**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
196
197**系统能力:** SystemCapability.ArkUI.ArkUI.Full
198
199**参数:**
200
201| 参数名 | 类型   | 必填 | 说明                                                         |
202| ------ | ------ | ---- | ------------------------------------------------------------ |
203| mode  | Optional\<[AnimationMode](#animationmode12枚举说明)\> | 是   | 点击TabBar页签时切换TabContent的动画形式。<br/>默认值:<br/>默认值是AnimationMode.CONTENT_FIRST,表示在点击TabBar切换TabContent时,先加载目标页内容,再开始切换动画。|
204
205### barPosition<sup>9+</sup>
206
207barPosition(value: BarPosition)
208
209设置Tabs的页签位置。
210
211**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
212
213**系统能力:** SystemCapability.ArkUI.ArkUI.Full
214
215**参数:**
216
217| 参数名 | 类型                               | 必填 | 说明                  |
218| ----- | ---------------------------------- | ---- | -------------------- |
219| value | [BarPosition](#barposition枚举说明)| 是  | 设置Tabs的页签位置。<br/>默认值:BarPosition.Start   |
220
221### divider<sup>10+</sup>
222
223divider(value: DividerStyle | null)
224
225设置区分TabBar和TabContent的分割线样式。
226
227**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
228
229**系统能力:** SystemCapability.ArkUI.ArkUI.Full
230
231**参数:**
232
233| 参数名 | 类型                                                      | 必填 | 说明                                                         |
234| ------ | --------------------------------------------------------- | ---- | ------------------------------------------------------------ |
235| value  | [DividerStyle](#dividerstyle10对象说明)&nbsp;\|&nbsp;null | 是   | 分割线样式,默认不显示分割线。<br/>DividerStyle: 分割线的样式;<br/>null: 不显示分割线。 |
236
237### fadingEdge<sup>10+</sup>
238
239fadingEdge(value: boolean)
240
241设置页签超过容器宽度时是否渐隐消失。建议配合barBackgroundColor属性一起使用,如果barBackgroundColor属性没有定义,会默认显示页签末端为白色的渐隐效果。
242
243**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
244
245**系统能力:** SystemCapability.ArkUI.ArkUI.Full
246
247**参数:**
248
249| 参数名 | 类型    | 必填 | 说明                                               |
250| ------ | ------- | ---- | -------------------------------------------------- |
251| value  | boolean | 是   | 页签超过容器宽度时是否渐隐消失。<br />默认值:true |
252
253### barOverlap<sup>10+</sup>
254
255barOverlap(value: boolean)
256
257设置TabBar是否背后变模糊并叠加在TabContent之上。
258
259**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
260
261**系统能力:** SystemCapability.ArkUI.ArkUI.Full
262
263**参数:**
264
265| 参数名 | 类型    | 必填 | 说明                                                         |
266| ------ | ------- | ---- | ------------------------------------------------------------ |
267| value  | boolean | 是   | TabBar是否背后变模糊并叠加在TabContent之上。当barOverlap设置为true时,TabBar默认模糊材质的BlurStyle值修改为'BlurStyle.COMPONENT_THICK'。<br />默认值:false |
268
269### barBackgroundColor<sup>10+</sup>
270
271barBackgroundColor(value: ResourceColor)
272
273设置TabBar的背景颜色。
274
275**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
276
277**系统能力:** SystemCapability.ArkUI.ArkUI.Full
278
279**参数:**
280
281| 参数名 | 类型                                       | 必填 | 说明                                 |
282| ------ | ------------------------------------------ | ---- | ------------------------------------ |
283| value  | [ResourceColor](ts-types.md#resourcecolor) | 是   | TabBar的背景颜色。<br />默认值:Color.Transparent,透明 |
284
285### barBackgroundBlurStyle<sup>11+</sup>
286
287barBackgroundBlurStyle(value: BlurStyle)
288
289设置TabBar的背景模糊材质。
290
291**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
292
293**系统能力:** SystemCapability.ArkUI.ArkUI.Full
294
295**参数:**
296
297| 参数名 | 类型                                         | 必填 | 说明                                     |
298| ------ | -------------------------------------------- | ---- | ---------------------------------------- |
299| value  | [BlurStyle](ts-universal-attributes-background.md#blurstyle9) | 是   | TabBar的背景模糊材质。<br />默认值:BlurStyle.NONE |
300
301### barGridAlign<sup>10+</sup>
302
303barGridAlign(value: BarGridColumnOptions)
304
305以栅格化方式设置TabBar的可见区域。具体参见BarGridColumnOptions对象。仅水平模式下有效,[不适用于XS、XL和XXL设备](../../../ui/arkts-layout-development-grid-layout.md#栅格系统断点)。
306
307**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
308
309**系统能力:** SystemCapability.ArkUI.ArkUI.Full
310
311**参数:**
312
313| 参数名 | 类型                                                    | 必填 | 说明                               |
314| ------ | ------------------------------------------------------- | ---- | ---------------------------------- |
315| value  | [BarGridColumnOptions](#bargridcolumnoptions10对象说明) | 是   | 以栅格化方式设置TabBar的可见区域。 |
316
317### edgeEffect<sup>12+</sup>
318
319edgeEffect(edgeEffect: Optional&lt;EdgeEffect&gt;)
320
321设置边缘回弹效果。
322
323**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
324
325**系统能力:** SystemCapability.ArkUI.ArkUI.Full
326
327**参数:**
328
329| 参数名 | 类型                                          | 必填 | 说明                                         |
330| ------ | --------------------------------------------- | ---- | -------------------------------------------- |
331| edgeEffect  | Optional&lt;[EdgeEffect](ts-appendix-enums.md#edgeeffect)&gt; | 是   | 边缘滑动效果。<br/>默认值:EdgeEffect.Spring |
332
333## DividerStyle<sup>10+</sup>对象说明
334
335分割线样式对象。
336
337**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
338
339**系统能力:** SystemCapability.ArkUI.ArkUI.Full
340
341| 名称          | 类型                                     | 必填   | 说明                                       |
342| ----------- | ---------------------------------------- | ---- | ---------------------------------------- |
343| strokeWidth | [Length](ts-types.md#length)             | 是    | 分割线的线宽(不支持百分比设置)。<br/>默认值:0.0<br/>单位:vp           |
344| color       | [ResourceColor](ts-types.md#resourcecolor) | 否    | 分割线的颜色。<br/>默认值:#33182431                |
345| startMargin | [Length](ts-types.md#length)             | 否    | 分割线与侧边栏顶端的距离(不支持百分比设置)。<br/>默认值:0.0<br/>单位:vp |
346| endMargin   | [Length](ts-types.md#length)             | 否    | 分割线与侧边栏底端的距离(不支持百分比设置)。<br/>默认值:0.0<br/>单位:vp |
347
348## BarGridColumnOptions<sup>10+</sup>对象说明
349
350TabBar栅格化方式设置的对象,包括栅格模式下的column边距和间隔,以及小、中、大屏下,页签占用的columns数量。
351
352**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
353
354**系统能力:** SystemCapability.ArkUI.ArkUI.Full
355
356| 名称          | 类型                                     | 必填   | 说明                                       |
357| ----------- | ---------------------------------------- | ---- | ---------------------------------------- |
358| margin | [Dimension](ts-types.md#dimension10)             | 否    | 栅格模式下的column边距(不支持百分比设置)。<br/>默认值:24.0<br/>单位:vp                        |
359| gutter      | [Dimension](ts-types.md#dimension10) | 否    | 栅格模式下的column间隔(不支持百分比设置)。<br/>默认值:24.0<br/>单位:vp                     |
360| sm | number            | 否    | 小屏下,页签占用的columns数量,必须是非负偶数。小屏为大于等于320vp但小于600vp。<br/>默认值为-1,代表页签占用TabBar全部宽度。 |
361| md   | number          | 否    | 中屏下,页签占用的columns数量,必须是非负偶数。中屏为大于等于600vp但小于800vp。<br/>默认值为-1,代表页签占用TabBar全部宽度。 |
362| lg   | number           | 否    | 大屏下,页签占用的columns数量,必须是非负偶数。大屏为大于等于840vp但小于1024vp。<br/>默认值为-1,代表页签占用TabBar全部宽度。 |
363
364## ScrollableBarModeOptions<sup>10+</sup>对象说明
365
366Scrollable模式下的TabBar的布局样式对象。
367
368**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
369
370**系统能力:** SystemCapability.ArkUI.ArkUI.Full
371
372| 名称          | 类型                                     | 必填   | 说明                                       |
373| ----------- | ---------------------------------------- | ---- | ---------------------------------------- |
374| margin | [Dimension](ts-types.md#dimension10)          | 否    | Scrollable模式下的TabBar的左右边距(不支持百分比设置)。<br/>默认值:0.0<br/>单位:vp                    |
375| nonScrollableLayoutStyle      | [LayoutStyle](#layoutstyle10枚举说明) | 否    | Scrollable模式下不滚动时的页签排布方式。<br/>默认值:LayoutStyle.ALWAYS_CENTER           |
376
377## BarMode枚举说明
378
379TabBar布局模式枚举。
380
381**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
382
383**系统能力:** SystemCapability.ArkUI.ArkUI.Full
384
385| 名称        | 值 | 说明                                     |
386| ---------- | -- | ---------------------------------------- |
387| Scrollable | 0  | 每一个TabBar均使用实际布局宽度,超过总长度(横向Tabs的barWidth,纵向Tabs的barHeight)后可滑动。 |
388| Fixed      | 1  | 所有TabBar平均分配barWidth宽度(纵向时平均分配barHeight高度)。 |
389
390## AnimationMode<sup>12+</sup>枚举说明
391
392点击TabBar页签时切换TabContent的动画形式枚举。
393
394**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
395
396**系统能力:** SystemCapability.ArkUI.ArkUI.Full
397
398| 名称          | 值   | 说明                                                         |
399| ------------- | ---- | ------------------------------------------------------------ |
400| CONTENT_FIRST | 0    | 先加载目标页内容,再开始切换动画                             |
401| ACTION_FIRST  | 1    | 先开始切换动画,再加载目标页内容;生效需要同时需要满足:Tabs的height、width没有设置成auto |
402| NO_ANIMATION  | 2    | 关闭默认动画                                                 |
403
404## LayoutStyle<sup>10+</sup>枚举说明
405
406Scrollable模式下不滚动时的页签排布方式枚举。
407
408**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
409
410**系统能力:** SystemCapability.ArkUI.ArkUI.Full
411
412| 名称         | 值 | 说明                                     |
413| ---------- | -- | ---------------------------------------- |
414| ALWAYS_CENTER | 0 | 当页签内容超过TabBar宽度时,TabBar可滚动。<br/>当页签内容不超过TabBar宽度时,TabBar不可滚动,页签紧凑居中。|
415| ALWAYS_AVERAGE_SPLIT | 1 | 当页签内容超过TabBar宽度时,TabBar可滚动。<br/>当页签内容不超过TabBar宽度时,TabBar不可滚动,且所有页签平均分配TabBar宽度。|
416| SPACE_BETWEEN_OR_CENTER      | 2 | 当页签内容超过TabBar宽度时,TabBar可滚动。<br/>当页签内容不超过TabBar宽度但超过TabBar宽度一半时,TabBar不可滚动,页签紧凑居中。<br/>当页签内容不超过TabBar宽度一半时,TabBar不可滚动,保证页签居中排列在TabBar宽度一半,且间距相同。|
417
418## 事件
419
420除支持[通用事件](ts-universal-events-click.md)外,还支持以下事件:
421
422### onChange
423
424onChange(event:&nbsp;(index:&nbsp;number)&nbsp;=&gt;&nbsp;void)
425
426Tab页签切换后触发的事件。
427
428触发该事件的条件:
429
4301、滑动页面进行页面切换时,组件滑动动画结束后触发。
431
4322、通过[控制器](#tabscontroller)API接口调用。
433
4343、通过[状态变量](../../../quick-start/arkts-state.md)构造的属性值进行修改。
435
4364、通过页签处点击触发。
437
438>  **说明:**
439>
440>  使用自定义页签时,在onChange事件中联动可能会导致滑动页面切换后才执行页签联动,引起自定义页签切换效果延迟。建议在[onAnimationStart](#onanimationstart11)中监听并刷新当前索引,以确保动效能够及时触发。具体实现可参考[示例1](#示例1自定义页签切换联动)。
441
442**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
443
444**系统能力:** SystemCapability.ArkUI.ArkUI.Full
445
446**参数:**
447
448| 参数名 | 类型   | 必填 | 说明                                   |
449| ------ | ------ | ---- | -------------------------------------- |
450| index  | number | 是   | 当前显示的index索引,索引从0开始计算。 |
451
452### onTabBarClick<sup>10+</sup>
453
454onTabBarClick(event:&nbsp;(index:&nbsp;number)&nbsp;=&gt;&nbsp;void)
455
456Tab页签点击后触发的事件。
457
458**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
459
460**系统能力:** SystemCapability.ArkUI.ArkUI.Full
461
462**参数:**
463
464| 参数名 | 类型   | 必填 | 说明                                 |
465| ------ | ------ | ---- | ------------------------------------ |
466| index  | number | 是   | 被点击的index索引,索引从0开始计算。 |
467
468### onAnimationStart<sup>11+</sup>
469
470onAnimationStart(handler: (index: number, targetIndex: number, event: TabsAnimationEvent) => void)
471
472切换动画开始时触发该回调。参数为动画开始前的index值(不是最终结束动画的index值)。当animationDuration为0时动画关闭,不触发该回调。
473
474**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
475
476**系统能力:** SystemCapability.ArkUI.ArkUI.Full
477
478**参数:**
479
480| 参数名      | 类型                                                   | 必填 | 说明                                                         |
481| ----------- | ------------------------------------------------------ | ---- | ------------------------------------------------------------ |
482| index       | number                                                 | 是   | 当前显示元素的索引。                                         |
483| targetIndex | number                                                 | 是   | 切换动画目标元素的索引。                                     |
484| event       | [TabsAnimationEvent](#tabsanimationevent11对象说明) | 是   | 动画相关信息,包括主轴方向上当前显示元素和目标元素相对Tabs起始位置的位移,以及离手速度。 |
485
486### onAnimationEnd<sup>11+</sup>
487
488onAnimationEnd(handler: (index: number, event: TabsAnimationEvent) => void)
489
490切换动画结束时触发该回调。当Tabs切换动效结束时触发,包括动画过程中手势中断。参数为动画结束后的index值。当animationDuration为0时动画关闭,不触发该回调。
491
492**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
493
494**系统能力:** SystemCapability.ArkUI.ArkUI.Full
495
496**参数:**
497
498| 参数名 | 类型                                                   | 必填 | 说明                                                         |
499| ------ | ------------------------------------------------------ | ---- | ------------------------------------------------------------ |
500| index  | number                                                 | 是   | 当前显示元素的索引。                                         |
501| event  | [TabsAnimationEvent](#tabsanimationevent11对象说明) | 是   | 动画相关信息,只返回主轴方向上当前显示元素相对于Tabs起始位置的位移。 |
502
503### onGestureSwipe<sup>11+</sup>
504
505onGestureSwipe(handler: (index: number, event: TabsAnimationEvent) => void)
506
507在页面跟手滑动过程中,逐帧触发该回调。
508
509**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
510
511**系统能力:** SystemCapability.ArkUI.ArkUI.Full
512
513**参数:**
514
515| 参数名 | 类型                                                   | 必填 | 说明                                                         |
516| ------ | ------------------------------------------------------ | ---- | ------------------------------------------------------------ |
517| index  | number                                                 | 是   | 当前显示元素的索引。                                         |
518| event  | [TabsAnimationEvent](#tabsanimationevent11对象说明) | 是   | 动画相关信息,只返回主轴方向上当前显示元素相对于Tabs起始位置的位移。 |
519
520### customContentTransition<sup>11+</sup>
521
522customContentTransition(delegate: (from: number, to: number) => TabContentAnimatedTransition \| undefined)
523
524自定义Tabs页面切换动画。
525
526使用说明:
527
5281、当使用自定义切换动画时,Tabs组件自带的默认切换动画会被禁用,同时,页面也无法跟手滑动。<br>2、当设置为undefined时,表示不使用自定义切换动画,仍然使用组件自带的默认切换动画。<br>3、当前自定义切换动画不支持打断。<br>4、目前自定义切换动画只支持两种场景触发:点击页签和调用TabsController.changeIndex()接口。<br>5、当使用自定义切换动画时,Tabs组件支持的事件中,除了onGestureSwipe,其他事件均支持。<br>6、onChange和onAnimationEnd事件的触发时机需要特殊说明:如果在第一次自定义动画执行过程中,触发了第二次自定义动画,那么在开始第二次自定义动画时,就会触发第一次自定义动画的onChange和onAnimationEnd事件。<br>7、当使用自定义动画时,参与动画的页面布局方式会改为Stack布局。如果开发者未主动设置相关页面的zIndex属性,那么所有页面的zIndex值是一样的,页面的渲染层级会按照在组件树上的顺序(即页面的index值顺序)确定。因此,开发者需要主动修改页面的zIndex属性,来控制页面的渲染层级。
529
530**卡片能力:** 从API version 11开始,该接口支持在ArkTS卡片中使用。
531
532**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
533
534**系统能力:** SystemCapability.ArkUI.ArkUI.Full
535
536**参数:**
537
538| 参数名 | 类型   | 必填 | 说明                            |
539| ------ | ------ | ---- | ------------------------------- |
540| from   | number | 是   | 动画开始时,当前页面的index值。 |
541| to     | number | 是   | 动画开始时,目标页面的index值。 |
542
543**返回值:**
544
545| 类型                                                         | 说明                     |
546| ------------------------------------------------------------ | ------------------------ |
547| [TabContentAnimatedTransition](#tabcontentanimatedtransition11)&nbsp;\|&nbsp;undefined | 自定义切换动画相关信息。 |
548
549### onContentWillChange<sup>12+</sup>
550
551onContentWillChange(handler: (currentIndex: number, comingIndex: number) => boolean)
552
553自定义Tabs页面切换拦截事件能力,新页面即将显示时触发该回调。
554
555触发该回调的条件:
556
5571、TabContent支持滑动时,滑动组件切换新页面时触发。
558
5592、通过TabsController.changeIndex接口切换新页面时触发。
560
5613、通过动态修改index属性值切换新页面时触发。
562
5634、通过点击TabBar页签切换新页面时触发。
564
5655、TabBar页签获焦后,通过键盘左右方向键等切换新页面时触发。
566
567**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
568
569**系统能力:** SystemCapability.ArkUI.ArkUI.Full
570
571**参数:**
572
573| 参数名       | 类型   | 必填 | 说明                                       |
574| ------------ | ------ | ---- | ------------------------------------------ |
575| currentIndex | number | 是   | 当前显示页面的index索引,索引从0开始计算。 |
576| comingIndex  | number | 是   | 将要显示的新页面的index索引。              |
577
578**返回值:**
579
580| 类型    | 说明                                                         |
581| ------- | ------------------------------------------------------------ |
582| boolean | 当回调函数handler的返回值为true时,Tabs可以切换到新页面。<br/>当回调函数handler的返回值为false时,Tabs无法切换到新页面,仍然显示原来页面内容。 |
583
584## TabsAnimationEvent<sup>11+</sup>对象说明
585
586Tabs组件动画相关信息集合。
587
588**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
589
590**系统能力:** SystemCapability.ArkUI.ArkUI.Full
591
592| 名称            | 类型      | 只读 | 可选 | 说明                                       |
593| ------------- | ---------- | ---- | ---- | ------------------------ |
594| currentOffset | number | 否 | 否 | Tabs当前显示元素在主轴方向上,相对于Tabs起始位置的位移。单位VP,默认值为0。|
595| targetOffset | number | 否 | 否 | Tabs动画目标元素在主轴方向上,相对于Tabs起始位置的位移。单位VP,默认值为0。|
596| velocity | number | 否 | 否 | Tabs离手动画开始时的离手速度。单位VP/S,默认值为0。|
597
598## TabContentAnimatedTransition<sup>11+</sup>
599
600Tabs自定义切换动画相关信息。
601
602**卡片能力:** 从API version 11开始,该接口支持在ArkTS卡片中使用。
603
604**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
605
606**系统能力:** SystemCapability.ArkUI.ArkUI.Full
607
608| 名称            | 类型         | 必填   | 说明                                       |
609| ------------- | ---------------------- | ---- |---------------------- |
610| timeout | number | 否 | Tabs自定义切换动画超时时间。从自定义动画开始切换计时,如果到达该时间后,开发者仍未调用[TabContentTransitionProxy](#tabcontenttransitionproxy11)的finishTransition接口通知Tabs组件自定义动画结束,那么组件就会认为此次自定义动画已结束,直接执行后续操作。单位ms,默认值为1000.|
611| transition | [Callback](./ts-types.md#callback12)\<[TabContentTransitionProxy](#tabcontenttransitionproxy11)> | 是 | 自定义切换动画具体内容。|
612
613## TabContentTransitionProxy<sup>11+</sup>
614
615Tabs自定义切换动画执行过程中,返回给开发者的proxy对象。开发者可通过该对象获取自定义动画的起始和目标页面信息,同时,也可以通过调用该对象的finishTransition接口通知Tabs组件自定义动画已结束。
616
617**卡片能力:** 从API version 11开始,该接口支持在ArkTS卡片中使用。
618
619**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
620
621**系统能力:** SystemCapability.ArkUI.ArkUI.Full
622
623### 属性
624
625| 名称  | 类型     | 只读 | 可选 | 说明                         |
626| ----- | ------- | ---- | ---- | --------------------------- |
627| from | number | 否 | 否 | 自定义动画起始页面对应的index值。|
628| to | number | 否 | 否 | 自定义动画目标页面对应的index值。|
629
630### finishTransition
631
632finishTransition(): void
633
634通知Tabs组件,此页面的自定义动画已结束。
635
636**卡片能力:** 从API version 11开始,该接口支持在ArkTS卡片中使用。
637
638**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
639
640**系统能力:** SystemCapability.ArkUI.ArkUI.Full
641
642## TabsController
643
644Tabs组件的控制器,用于控制Tabs组件进行页签切换。不支持一个TabsController控制多个Tabs组件。
645
646**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
647
648**系统能力:** SystemCapability.ArkUI.ArkUI.Full
649
650### 导入对象
651
652```ts
653let controller: TabsController = new TabsController()
654```
655
656### constructor
657
658constructor()
659
660TabsController的构造函数。
661
662**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
663
664**系统能力:** SystemCapability.ArkUI.ArkUI.Full
665
666### changeIndex
667
668changeIndex(value: number): void
669
670控制Tabs切换到指定页签。
671
672**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
673
674**系统能力:** SystemCapability.ArkUI.ArkUI.Full
675
676**参数:**
677
678| 参数名   | 类型   | 必填   | 说明                                     |
679| ----- | ------ | ---- | ---------------------------------------- |
680| value | number | 是    | 页签在Tabs里的索引值,索引值从0开始。<br/>**说明:** <br/>设置小于0或大于最大数量的值时,取默认值0。 |
681
682### preloadItems<sup>12+</sup>
683
684preloadItems(indices: Optional\<Array\<number>>): Promise\<void>
685
686控制Tabs预加载指定子节点。调用该接口后会一次性加载所有指定的子节点,因此为了性能考虑,建议分批加载子节点。
687
688**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
689
690**系统能力:** SystemCapability.ArkUI.ArkUI.Full
691
692**参数:**
693
694| 参数名   | 类型   | 必填   | 说明                                     |
695| ----- | ------ | ---- | ---------------------------------------- |
696| indices | Optional\<Array\<number>> | 是 | 需预加载的子节点的下标数组。<br/>默认值:空数组。 |
697
698**返回值:**
699
700| 类型                                                         | 说明                     |
701| ------------------------------------------------------------ | ------------------------ |
702| Promise\<void> | 预加载完成后触发的回调。 |
703
704**错误码:**
705
706以下错误码的详细介绍请参见[通用错误码](../../errorcode-universal.md)错误码。
707
708| 错误码ID   | 错误信息                                      |
709| --------   | -------------------------------------------- |
710| 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. |
711
712### setTabBarTranslate<sup>13+</sup>
713
714setTabBarTranslate(translate: TranslateOptions): void
715
716设置TabBar的平移距离。
717
718> **说明:**
719>
720> 当使用bindTabsToScrollable或bindTabsToNestedScrollable等接口绑定了Tabs组件和可滚动容器组件后,在滑动可滚动容器组件时,会触发所有与其绑定的Tabs组件的TabBar的显示和隐藏动效,调用setTabBarTranslate接口设置的TabBar平移距离会失效。因此不建议同时使用bindTabsToScrollable、bindTabsToNestedScrollable和setTabBarTranslate接口。
721>
722
723**原子化服务API:** 从API version 13开始,该接口支持在原子化服务中使用。
724
725**系统能力:** SystemCapability.ArkUI.ArkUI.Full
726
727**参数:**
728
729| 参数名   | 类型   | 必填   | 说明                                     |
730| ----- | ------ | ---- | ---------------------------------------- |
731| translate | [TranslateOptions](ts-universal-attributes-transformation.md#translateoptions对象说明) | 是 | 设置TabBar的平移距离。 |
732
733### setTabBarOpacity<sup>13+</sup>
734
735setTabBarOpacity(opacity: number): void
736
737设置TabBar的不透明度。
738
739> **说明:**
740>
741> 当使用bindTabsToScrollable或bindTabsToNestedScrollable等接口绑定了Tabs组件和可滚动容器组件后,在滑动可滚动容器组件时,会触发所有与其绑定的Tabs组件的TabBar的显示和隐藏动效,调用setTabBarOpacity接口设置的TabBar不透明度会失效。因此不建议同时使用bindTabsToScrollable、bindTabsToNestedScrollable和setTabBarOpacity接口。
742>
743
744**原子化服务API:** 从API version 13开始,该接口支持在原子化服务中使用。
745
746**系统能力:** SystemCapability.ArkUI.ArkUI.Full
747
748**参数:**
749
750| 参数名   | 类型   | 必填   | 说明                                     |
751| ----- | ------ | ---- | ---------------------------------------- |
752| opacity | number | 是 | 设置TabBar的不透明度,取值范围为[0.0, 1.0]。 |
753
754## 示例
755
756### 示例1(自定义页签切换联动)
757
758本示例通过onAnimationStart、onChange实现切换时自定义tabBar和TabContent的联动。
759
760```ts
761// xxx.ets
762@Entry
763@Component
764struct TabsExample {
765  @State fontColor: string = '#182431'
766  @State selectedFontColor: string = '#007DFF'
767  @State currentIndex: number = 0
768  @State selectedIndex: number = 0
769  private controller: TabsController = new TabsController()
770
771  @Builder tabBuilder(index: number, name: string) {
772    Column() {
773      Text(name)
774        .fontColor(this.selectedIndex === index ? this.selectedFontColor : this.fontColor)
775        .fontSize(16)
776        .fontWeight(this.selectedIndex === index ? 500 : 400)
777        .lineHeight(22)
778        .margin({ top: 17, bottom: 7 })
779      Divider()
780        .strokeWidth(2)
781        .color('#007DFF')
782        .opacity(this.selectedIndex === index ? 1 : 0)
783    }.width('100%')
784  }
785
786  build() {
787    Column() {
788      Tabs({ barPosition: BarPosition.Start, index: this.currentIndex, controller: this.controller }) {
789        TabContent() {
790          Column().width('100%').height('100%').backgroundColor('#00CB87')
791        }.tabBar(this.tabBuilder(0, 'green'))
792
793        TabContent() {
794          Column().width('100%').height('100%').backgroundColor('#007DFF')
795        }.tabBar(this.tabBuilder(1, 'blue'))
796
797        TabContent() {
798          Column().width('100%').height('100%').backgroundColor('#FFBF00')
799        }.tabBar(this.tabBuilder(2, 'yellow'))
800
801        TabContent() {
802          Column().width('100%').height('100%').backgroundColor('#E67C92')
803        }.tabBar(this.tabBuilder(3, 'pink'))
804      }
805      .vertical(false)
806      .barMode(BarMode.Fixed)
807      .barWidth(360)
808      .barHeight(56)
809      .animationDuration(400)
810      .onChange((index: number) => {
811        // currentIndex控制TabContent显示页签
812        this.currentIndex = index
813        this.selectedIndex = index
814      })
815      .onAnimationStart((index: number, targetIndex: number, event: TabsAnimationEvent) => {
816        if (index === targetIndex) {
817          return
818        }
819        // selectedIndex控制自定义TabBar内Image和Text颜色切换
820        this.selectedIndex = targetIndex
821      })
822      .width(360)
823      .height(296)
824      .margin({ top: 52 })
825      .backgroundColor('#F1F3F5')
826    }.width('100%')
827  }
828}
829```
830
831![tabs2](figures/tabs2.gif)
832
833### 示例2(分割线基本属性)
834
835本示例通过divider实现了分割线各种属性的展示。
836
837```ts
838// xxx.ets
839@Entry
840@Component
841struct TabsDivider1 {
842  private controller1: TabsController = new TabsController()
843  @State dividerColor: string = 'red'
844  @State strokeWidth: number = 2
845  @State startMargin: number = 0
846  @State endMargin: number = 0
847  @State nullFlag: boolean = false
848
849  build() {
850    Column() {
851      Tabs({ controller: this.controller1 }) {
852        TabContent() {
853          Column().width('100%').height('100%').backgroundColor(Color.Pink)
854        }.tabBar('pink')
855
856        TabContent() {
857          Column().width('100%').height('100%').backgroundColor(Color.Yellow)
858        }.tabBar('yellow')
859
860        TabContent() {
861          Column().width('100%').height('100%').backgroundColor(Color.Blue)
862        }.tabBar('blue')
863
864        TabContent() {
865          Column().width('100%').height('100%').backgroundColor(Color.Green)
866        }.tabBar('green')
867
868        TabContent() {
869          Column().width('100%').height('100%').backgroundColor(Color.Red)
870        }.tabBar('red')
871      }
872      .vertical(true)
873      .scrollable(true)
874      .barMode(BarMode.Fixed)
875      .barWidth(70)
876      .barHeight(200)
877      .animationDuration(400)
878      .onChange((index: number) => {
879        console.info(index.toString())
880      })
881      .height('200vp')
882      .margin({ bottom: '12vp' })
883      .divider(this.nullFlag ? null : {
884        strokeWidth: this.strokeWidth,
885        color: this.dividerColor,
886        startMargin: this.startMargin,
887        endMargin: this.endMargin
888      })
889
890      Button('常规Divider').width('100%').margin({ bottom: '12vp' })
891        .onClick(() => {
892          this.nullFlag = false;
893          this.strokeWidth = 2;
894          this.dividerColor = 'red';
895          this.startMargin = 0;
896          this.endMargin = 0;
897        })
898      Button('空Divider').width('100%').margin({ bottom: '12vp' })
899        .onClick(() => {
900          this.nullFlag = true
901        })
902      Button('颜色变为蓝色').width('100%').margin({ bottom: '12vp' })
903        .onClick(() => {
904          this.dividerColor = 'blue'
905        })
906      Button('宽度增加').width('100%').margin({ bottom: '12vp' })
907        .onClick(() => {
908          this.strokeWidth += 2
909        })
910      Button('宽度减小').width('100%').margin({ bottom: '12vp' })
911        .onClick(() => {
912          if (this.strokeWidth > 2) {
913            this.strokeWidth -= 2
914          }
915        })
916      Button('上边距增加').width('100%').margin({ bottom: '12vp' })
917        .onClick(() => {
918          this.startMargin += 2
919        })
920      Button('上边距减少').width('100%').margin({ bottom: '12vp' })
921        .onClick(() => {
922          if (this.startMargin > 2) {
923            this.startMargin -= 2
924          }
925        })
926      Button('下边距增加').width('100%').margin({ bottom: '12vp' })
927        .onClick(() => {
928          this.endMargin += 2
929        })
930      Button('下边距减少').width('100%').margin({ bottom: '12vp' })
931        .onClick(() => {
932          if (this.endMargin > 2) {
933            this.endMargin -= 2
934          }
935        })
936    }.padding({ top: '24vp', left: '24vp', right: '24vp' })
937  }
938}
939```
940
941![tabs3](figures/tabs3.gif)
942
943### 示例3(设置TabBar渐隐)
944
945本示例通过fadingEdge实现了切换子页签渐隐和不渐隐。
946
947```ts
948// xxx.ets
949@Entry
950@Component
951struct TabsOpaque {
952  @State message: string = 'Hello World'
953  private controller: TabsController = new TabsController()
954  private controller1: TabsController = new TabsController()
955  @State selfFadingFade: boolean = true;
956
957  build() {
958    Column() {
959      Button('子页签设置渐隐').width('100%').margin({ bottom: '12vp' })
960        .onClick((event?: ClickEvent) => {
961          this.selfFadingFade = true;
962        })
963      Button('子页签设置不渐隐').width('100%').margin({ bottom: '12vp' })
964        .onClick((event?: ClickEvent) => {
965          this.selfFadingFade = false;
966        })
967      Tabs({ barPosition: BarPosition.End, controller: this.controller }) {
968        TabContent() {
969          Column().width('100%').height('100%').backgroundColor(Color.Pink)
970        }.tabBar('pink')
971
972        TabContent() {
973          Column().width('100%').height('100%').backgroundColor(Color.Yellow)
974        }.tabBar('yellow')
975
976        TabContent() {
977          Column().width('100%').height('100%').backgroundColor(Color.Blue)
978        }.tabBar('blue')
979
980        TabContent() {
981          Column().width('100%').height('100%').backgroundColor(Color.Green)
982        }.tabBar('green')
983
984        TabContent() {
985          Column().width('100%').height('100%').backgroundColor(Color.Green)
986        }.tabBar('green')
987
988        TabContent() {
989          Column().width('100%').height('100%').backgroundColor(Color.Green)
990        }.tabBar('green')
991
992        TabContent() {
993          Column().width('100%').height('100%').backgroundColor(Color.Green)
994        }.tabBar('green')
995
996        TabContent() {
997          Column().width('100%').height('100%').backgroundColor(Color.Green)
998        }.tabBar('green')
999      }
1000      .vertical(false)
1001      .scrollable(true)
1002      .barMode(BarMode.Scrollable)
1003      .barHeight(80)
1004      .animationDuration(400)
1005      .onChange((index: number) => {
1006        console.info(index.toString())
1007      })
1008      .fadingEdge(this.selfFadingFade)
1009      .height('30%')
1010      .width('100%')
1011
1012      Tabs({ barPosition: BarPosition.Start, controller: this.controller1 }) {
1013        TabContent() {
1014          Column().width('100%').height('100%').backgroundColor(Color.Pink)
1015        }.tabBar('pink')
1016
1017        TabContent() {
1018          Column().width('100%').height('100%').backgroundColor(Color.Yellow)
1019        }.tabBar('yellow')
1020
1021        TabContent() {
1022          Column().width('100%').height('100%').backgroundColor(Color.Blue)
1023        }.tabBar('blue')
1024
1025        TabContent() {
1026          Column().width('100%').height('100%').backgroundColor(Color.Green)
1027        }.tabBar('green')
1028
1029        TabContent() {
1030          Column().width('100%').height('100%').backgroundColor(Color.Green)
1031        }.tabBar('green')
1032
1033        TabContent() {
1034          Column().width('100%').height('100%').backgroundColor(Color.Green)
1035        }.tabBar('green')
1036      }
1037      .vertical(true)
1038      .scrollable(true)
1039      .barMode(BarMode.Scrollable)
1040      .barHeight(200)
1041      .barWidth(80)
1042      .animationDuration(400)
1043      .onChange((index: number) => {
1044        console.info(index.toString())
1045      })
1046      .fadingEdge(this.selfFadingFade)
1047      .height('30%')
1048      .width('100%')
1049    }
1050    .padding({ top: '24vp', left: '24vp', right: '24vp' })
1051  }
1052}
1053```
1054
1055![tabs4](figures/tabs4.gif)
1056
1057### 示例4(设置TabBar叠加在TabContent内容上)
1058
1059本示例通过barOverlap实现了TabBar是否背后变模糊并叠加在TabContent之上。
1060
1061```ts
1062// xxx.ets
1063@Entry
1064@Component
1065struct barHeightTest {
1066  @State arr: number[] = [0, 1, 2, 3]
1067  @State barOverlap: boolean = true;
1068  build() {
1069    Column() {
1070      Text(`barOverlap ${this.barOverlap}`).fontSize(16)
1071      Button("barOverlap变化").width('100%').margin({ bottom: '12vp' })
1072        .onClick((event?: ClickEvent) => {
1073          if (this.barOverlap) {
1074            this.barOverlap = false;
1075          } else {
1076            this.barOverlap = true;
1077          }
1078        })
1079
1080      Tabs({ barPosition: BarPosition.End }) {
1081        TabContent() {
1082          Column() {
1083            List({ space: 10 }) {
1084              ForEach(this.arr, (item: number) => {
1085                ListItem() {
1086                  Text("item" + item).width('80%').height(200).fontSize(16).textAlign(TextAlign.Center).backgroundColor('#fff8b81e')
1087                }
1088              }, (item: string) => item)
1089            }.width('100%').height('100%')
1090            .lanes(2).alignListItem(ListItemAlign.Center)
1091          }.width('100%').height('100%')
1092          .backgroundColor(Color.Pink)
1093        }
1094        .tabBar(new BottomTabBarStyle($r('sys.media.ohos_icon_mask_svg'), "测试0"))
1095      }
1096      .scrollable(false)
1097      .height('60%')
1098      .barOverlap(this.barOverlap)
1099    }
1100    .height(500)
1101    .padding({ top: '24vp', left: '24vp', right: '24vp' })
1102  }
1103}
1104```
1105
1106![tabs5](figures/tabs5.gif)
1107
1108### 示例5(设置TabBar栅格化可见区域)
1109
1110本示例通过barGridAlign实现了以栅格化方式设置TabBar的可见区域。
1111
1112```ts
1113// xxx.ets
1114@Entry
1115@Component
1116struct TabsExample5 {
1117  private controller: TabsController = new TabsController()
1118  @State gridMargin: number = 10
1119  @State gridGutter: number = 10
1120  @State sm: number = -2
1121  @State clickedContent: string = "";
1122
1123  build() {
1124    Column() {
1125      Row() {
1126        Button("gridMargin+10 " + this.gridMargin)
1127          .width('47%')
1128          .height(50)
1129          .margin({ top: 5 })
1130          .onClick((event?: ClickEvent) => {
1131            this.gridMargin += 10
1132          })
1133          .margin({ right: '6%', bottom: '12vp' })
1134        Button("gridMargin-10 " + this.gridMargin)
1135          .width('47%')
1136          .height(50)
1137          .margin({ top: 5 })
1138          .onClick((event?: ClickEvent) => {
1139            this.gridMargin -= 10
1140          })
1141          .margin({ bottom: '12vp' })
1142      }
1143
1144      Row() {
1145        Button("gridGutter+10 " + this.gridGutter)
1146          .width('47%')
1147          .height(50)
1148          .margin({ top: 5 })
1149          .onClick((event?: ClickEvent) => {
1150            this.gridGutter += 10
1151          })
1152          .margin({ right: '6%', bottom: '12vp' })
1153        Button("gridGutter-10 " + this.gridGutter)
1154          .width('47%')
1155          .height(50)
1156          .margin({ top: 5 })
1157          .onClick((event?: ClickEvent) => {
1158            this.gridGutter -= 10
1159          })
1160          .margin({ bottom: '12vp' })
1161      }
1162
1163      Row() {
1164        Button("sm+2 " + this.sm)
1165          .width('47%')
1166          .height(50)
1167          .margin({ top: 5 })
1168          .onClick((event?: ClickEvent) => {
1169            this.sm += 2
1170          })
1171          .margin({ right: '6%' })
1172        Button("sm-2 " + this.sm).width('47%').height(50).margin({ top: 5 })
1173          .onClick((event?: ClickEvent) => {
1174            this.sm -= 2
1175          })
1176      }
1177
1178      Text("点击内容:" + this.clickedContent).width('100%').height(200).margin({ top: 5 })
1179
1180
1181      Tabs({ barPosition: BarPosition.End, controller: this.controller }) {
1182        TabContent() {
1183          Column().width('100%').height('100%').backgroundColor(Color.Pink)
1184        }.tabBar(BottomTabBarStyle.of($r("sys.media.ohos_app_icon"), "1"))
1185
1186        TabContent() {
1187          Column().width('100%').height('100%').backgroundColor(Color.Green)
1188        }.tabBar(BottomTabBarStyle.of($r("sys.media.ohos_app_icon"), "2"))
1189
1190        TabContent() {
1191          Column().width('100%').height('100%').backgroundColor(Color.Blue)
1192        }.tabBar(BottomTabBarStyle.of($r("sys.media.ohos_app_icon"), "3"))
1193      }
1194      .width('350vp')
1195      .animationDuration(300)
1196      .height('60%')
1197      .barGridAlign({ sm: this.sm, margin: this.gridMargin, gutter: this.gridGutter })
1198      .backgroundColor(0xf1f3f5)
1199      .onTabBarClick((index: number) => {
1200        this.clickedContent += "now index " + index + " is clicked\n";
1201      })
1202    }
1203    .width('100%')
1204    .height(500)
1205    .margin({ top: 5 })
1206    .padding('10vp')
1207  }
1208}
1209```
1210
1211![tabs5](figures/tabs6.gif)
1212
1213### 示例6(设置Scrollable模式下的TabBar的布局样式)
1214
1215本示例实现了barMode的ScrollableBarModeOptions参数,该参数仅在Scrollable模式下有效。
1216
1217```ts
1218// xxx.ets
1219@Entry
1220@Component
1221struct TabsExample6 {
1222  private controller: TabsController = new TabsController()
1223  @State scrollMargin: number = 0
1224  @State layoutStyle: LayoutStyle = LayoutStyle.ALWAYS_CENTER
1225  @State text: string = "文本"
1226
1227  build() {
1228    Column() {
1229      Row() {
1230        Button("scrollMargin+10 " + this.scrollMargin)
1231          .width('47%')
1232          .height(50)
1233          .margin({ top: 5 })
1234          .onClick((event?: ClickEvent) => {
1235            this.scrollMargin += 10
1236          })
1237          .margin({ right: '6%', bottom: '12vp' })
1238        Button("scrollMargin-10 " + this.scrollMargin)
1239          .width('47%')
1240          .height(50)
1241          .margin({ top: 5 })
1242          .onClick((event?: ClickEvent) => {
1243            this.scrollMargin -= 10
1244          })
1245          .margin({ bottom: '12vp' })
1246      }
1247
1248      Row() {
1249        Button("文本增加 ")
1250          .width('47%')
1251          .height(50)
1252          .margin({ top: 5 })
1253          .onClick((event?: ClickEvent) => {
1254            this.text += '文本增加'
1255          })
1256          .margin({ right: '6%', bottom: '12vp' })
1257        Button("文本重置")
1258          .width('47%')
1259          .height(50)
1260          .margin({ top: 5 })
1261          .onClick((event?: ClickEvent) => {
1262            this.text = "文本"
1263          })
1264          .margin({ bottom: '12vp' })
1265      }
1266
1267      Row() {
1268        Button("layoutStyle.ALWAYS_CENTER")
1269          .width('100%')
1270          .height(50)
1271          .margin({ top: 5 })
1272          .fontSize(15)
1273          .onClick((event?: ClickEvent) => {
1274            this.layoutStyle = LayoutStyle.ALWAYS_CENTER;
1275          })
1276          .margin({ bottom: '12vp' })
1277      }
1278
1279      Row() {
1280        Button("layoutStyle.ALWAYS_AVERAGE_SPLIT")
1281          .width('100%')
1282          .height(50)
1283          .margin({ top: 5 })
1284          .fontSize(15)
1285          .onClick((event?: ClickEvent) => {
1286            this.layoutStyle = LayoutStyle.ALWAYS_AVERAGE_SPLIT;
1287          })
1288          .margin({ bottom: '12vp' })
1289      }
1290
1291      Row() {
1292        Button("layoutStyle.SPACE_BETWEEN_OR_CENTER")
1293          .width('100%')
1294          .height(50)
1295          .margin({ top: 5 })
1296          .fontSize(15)
1297          .onClick((event?: ClickEvent) => {
1298            this.layoutStyle = LayoutStyle.SPACE_BETWEEN_OR_CENTER;
1299          })
1300          .margin({ bottom: '12vp' })
1301      }
1302
1303      Tabs({ barPosition: BarPosition.End, controller: this.controller }) {
1304        TabContent() {
1305          Column().width('100%').height('100%').backgroundColor(Color.Pink)
1306        }.tabBar(SubTabBarStyle.of(this.text))
1307
1308        TabContent() {
1309          Column().width('100%').height('100%').backgroundColor(Color.Green)
1310        }.tabBar(SubTabBarStyle.of(this.text))
1311
1312        TabContent() {
1313          Column().width('100%').height('100%').backgroundColor(Color.Blue)
1314        }.tabBar(SubTabBarStyle.of(this.text))
1315      }
1316      .animationDuration(300)
1317      .height('60%')
1318      .backgroundColor(0xf1f3f5)
1319      .barMode(BarMode.Scrollable, { margin: this.scrollMargin, nonScrollableLayoutStyle: this.layoutStyle })
1320    }
1321    .width('100%')
1322    .height(500)
1323    .margin({ top: 5 })
1324    .padding('24vp')
1325  }
1326}
1327```
1328
1329![tabs5](figures/tabs7.gif)
1330
1331### 示例7(自定义Tabs页面切换动画)
1332
1333本示例通过customContentTransition实现了自定义Tabs页面的切换动画。
1334
1335```ts
1336// xxx.ets
1337interface itemType {
1338  text: string,
1339  backgroundColor: Color
1340}
1341
1342@Entry
1343@Component
1344struct TabsCustomAnimationExample {
1345  @State data: itemType[] = [
1346    {
1347      text: 'Red',
1348      backgroundColor: Color.Red
1349    },
1350    {
1351      text: 'Yellow',
1352      backgroundColor: Color.Yellow
1353    },
1354    {
1355      text: 'Blue',
1356      backgroundColor: Color.Blue
1357    }]
1358  @State opacityList: number[] = []
1359  @State scaleList: number[] = []
1360
1361  private durationList: number[] = []
1362  private timeoutList: number[] = []
1363  private customContentTransition: (from: number, to: number) => TabContentAnimatedTransition = (from: number, to: number) => {
1364    let tabContentAnimatedTransition = {
1365      timeout: this.timeoutList[from],
1366      transition: (proxy: TabContentTransitionProxy) => {
1367        this.scaleList[from] = 1.0
1368        this.scaleList[to] = 0.5
1369        this.opacityList[from] = 1.0
1370        this.opacityList[to] = 0.5
1371        animateTo({
1372          duration: this.durationList[from],
1373          onFinish: () => {
1374            proxy.finishTransition()
1375          }
1376        }, () => {
1377          this.scaleList[from] = 0.5
1378          this.scaleList[to] = 1.0
1379          this.opacityList[from] = 0.5
1380          this.opacityList[to] = 1.0
1381        })
1382      }
1383    } as TabContentAnimatedTransition
1384    return tabContentAnimatedTransition
1385  }
1386
1387  aboutToAppear(): void {
1388    let duration = 1000
1389    let timeout = 1000
1390    for (let i = 1; i <= this.data.length; i++) {
1391      this.opacityList.push(1.0)
1392      this.scaleList.push(1.0)
1393      this.durationList.push(duration * i)
1394      this.timeoutList.push(timeout * i)
1395    }
1396  }
1397
1398  build() {
1399    Column() {
1400      Tabs() {
1401        ForEach(this.data, (item: itemType, index: number) => {
1402          TabContent() {}
1403          .tabBar(item.text)
1404          .backgroundColor(item.backgroundColor)
1405          // 自定义动画变化透明度、缩放页面等
1406          .opacity(this.opacityList[index])
1407          .scale({ x: this.scaleList[index], y: this.scaleList[index] })
1408        })
1409      }
1410      .backgroundColor(0xf1f3f5)
1411      .width('100%')
1412      .height(500)
1413      .customContentTransition(this.customContentTransition)
1414    }
1415  }
1416}
1417```
1418
1419![tabs5](figures/tabs8.gif)
1420
1421### 示例8(页面切换拦截)
1422
1423本示例通过onContentWillChange实现了自定义页面手势滑动切换拦截。
1424
1425```ts
1426//xxx.ets
1427@Entry
1428@Component
1429struct TabsExample {
1430  @State selectedIndex: number = 2
1431  @State currentIndex: number = 2
1432  private controller: TabsController = new TabsController()
1433  @Builder tabBuilder(title: string,targetIndex: number) {
1434    Column(){
1435      Text(title).fontColor(this.selectedIndex === targetIndex ? '#1698CE' : '#6B6B6B')
1436    }.width('100%')
1437    .height(50)
1438    .justifyContent(FlexAlign.Center)
1439  }
1440  build() {
1441    Column() {
1442      Tabs({ barPosition: BarPosition.End, index: this.currentIndex, controller: this.controller }) {
1443        TabContent() {
1444          Column(){
1445            Text('首页的内容')
1446          }.width('100%').height('100%').backgroundColor('#00CB87').justifyContent(FlexAlign.Center)
1447        }.tabBar(this.tabBuilder('首页',0))
1448
1449        TabContent() {
1450          Column(){
1451            Text('发现的内容')
1452          }.width('100%').height('100%').backgroundColor('#007DFF').justifyContent(FlexAlign.Center)
1453        }.tabBar(this.tabBuilder('发现',1))
1454
1455        TabContent() {
1456          Column(){
1457            Text('推荐的内容')
1458          }.width('100%').height('100%').backgroundColor('#FFBF00').justifyContent(FlexAlign.Center)
1459        }.tabBar(this.tabBuilder('推荐',2))
1460
1461        TabContent() {
1462          Column(){
1463            Text('我的内容')
1464          }.width('100%').height('100%').backgroundColor('#E67C92').justifyContent(FlexAlign.Center)
1465        }.tabBar(this.tabBuilder('我的',3))
1466      }
1467      .vertical(false)
1468      .barMode(BarMode.Fixed)
1469      .barWidth(360)
1470      .barHeight(60)
1471      .animationDuration(0)
1472      .onChange((index: number) => {
1473        this.currentIndex = index
1474        this.selectedIndex = index
1475      })
1476      .width(360)
1477      .height(600)
1478      .backgroundColor('#F1F3F5')
1479      .scrollable(true)
1480      .onContentWillChange((currentIndex, comingIndex) => {
1481        if (comingIndex == 2) {
1482          return false
1483        }
1484        return true
1485      })
1486
1487      Button('动态修改index').width('50%').margin({ top: 20 })
1488        .onClick(()=>{
1489          this.currentIndex = (this.currentIndex + 1) % 4
1490        })
1491
1492      Button('changeIndex').width('50%').margin({ top: 20 })
1493        .onClick(()=>{
1494          this.currentIndex = (this.currentIndex + 1) % 4
1495          this.controller.changeIndex(this.currentIndex)
1496        })
1497    }.width('100%')
1498  }
1499}
1500```
1501
1502![tabs9](figures/tabs9.gif)
1503
1504### 示例9(自定义TabBar切换动画)
1505
1506本示例通过onChange、onAnimationStart、onAnimationEnd、onGestureSwipe等接口实现了自定义TabBar的切换动画。
1507
1508<!--code_no_check-->
1509
1510```ts
1511// EntryAbility.ets
1512import { Configuration, UIAbility } from '@kit.AbilityKit'
1513import { i18n } from '@kit.LocalizationKit'
1514import { CommonUtil } from '../common/CommonUtil'
1515
1516export default class EntryAbility extends UIAbility {
1517  onConfigurationUpdate(newConfig: Configuration): void {
1518    // 监听系统配置变化
1519    if (newConfig.language) {
1520      CommonUtil.setIsRTL(i18n.isRTL(newConfig.language))
1521    }
1522  }
1523}
1524```
1525
1526<!--code_no_check-->
1527
1528```ts
1529// CommonUtil.ets
1530import { i18n, intl } from '@kit.LocalizationKit'
1531
1532export class CommonUtil {
1533  private static isRTL: boolean = i18n.isRTL((new intl.Locale()).language)
1534
1535  public static setIsRTL(isRTL: boolean): void {
1536    CommonUtil.isRTL = isRTL
1537  }
1538
1539  public static getIsRTL(): boolean {
1540    return CommonUtil.isRTL
1541  }
1542}
1543```
1544
1545<!--code_no_check-->
1546
1547```ts
1548// xxx.ets
1549import { LengthMetrics } from '@kit.ArkUI'
1550import { CommonUtil } from '../common/CommonUtil'
1551
1552@Entry
1553@Component
1554struct TabsExample {
1555  @State colorArray: [string, string][] =
1556    [['green', '#00CB87'], ['blue', '#007DFF'], ['yellow', '#FFBF00'], ['pink', '#E67C92']]
1557  @State currentIndex: number = 0
1558  @State animationDuration: number = 300
1559  @State indicatorLeftMargin: number = 0
1560  @State indicatorWidth: number = 0
1561  private tabsWidth: number = 0
1562  private textInfos: [number, number][] = []
1563  private isStartAnimateTo: boolean = false
1564
1565  aboutToAppear():void {
1566    for (let i = 0; i < this.colorArray.length; i++) {
1567      this.textInfos.push([0, 0]);
1568    }
1569  }
1570
1571  @Builder
1572  tabBuilder(index: number, name: string) {
1573    Column() {
1574      Text(name)
1575        .fontSize(16)
1576        .fontColor(this.currentIndex === index ? '#007DFF' : '#182431')
1577        .fontWeight(this.currentIndex === index ? 500 : 400)
1578        .id(index.toString())
1579        .onAreaChange((oldValue: Area, newValue: Area) => {
1580          this.textInfos[index] = [newValue.globalPosition.x as number, newValue.width as number]
1581          if (!this.isStartAnimateTo && this.currentIndex === index && this.tabsWidth > 0) {
1582            this.setIndicatorAttr(this.textInfos[this.currentIndex][0], this.textInfos[this.currentIndex][1])
1583          }
1584        })
1585    }.width('100%')
1586  }
1587
1588  build() {
1589    Stack({ alignContent: Alignment.TopStart }) {
1590      Tabs({ barPosition: BarPosition.Start }) {
1591        ForEach(this.colorArray, (item: [string, string], index:number) => {
1592          TabContent() {
1593            Column().width('100%').height('100%').backgroundColor(item[1])
1594          }.tabBar(this.tabBuilder(index, item[0]))
1595        })
1596      }
1597      .onAreaChange((oldValue: Area, newValue: Area)=> {
1598        this.tabsWidth = newValue.width as number
1599        if (!this.isStartAnimateTo) {
1600          this.setIndicatorAttr(this.textInfos[this.currentIndex][0], this.textInfos[this.currentIndex][1])
1601        }
1602      })
1603      .barWidth('100%')
1604      .barHeight(56)
1605      .width('100%')
1606      .height(296)
1607      .backgroundColor('#F1F3F5')
1608      .animationDuration(this.animationDuration)
1609      .onChange((index: number) => {
1610        this.currentIndex = index // 监听索引index的变化,实现页签内容的切换。
1611      })
1612      .onAnimationStart((index: number, targetIndex: number, event: TabsAnimationEvent) => {
1613        // 切换动画开始时触发该回调。下划线跟着页面一起滑动,同时宽度渐变。
1614        this.currentIndex = targetIndex
1615        this.startAnimateTo(this.animationDuration, this.textInfos[targetIndex][0], this.textInfos[targetIndex][1])
1616      })
1617      .onAnimationEnd((index: number, event: TabsAnimationEvent) => {
1618        // 切换动画结束时触发该回调。下划线动画停止。
1619        let currentIndicatorInfo = this.getCurrentIndicatorInfo(index, event)
1620        this.startAnimateTo(0, currentIndicatorInfo.left, currentIndicatorInfo.width)
1621      })
1622      .onGestureSwipe((index: number, event: TabsAnimationEvent) => {
1623        // 在页面跟手滑动过程中,逐帧触发该回调。
1624        let currentIndicatorInfo = this.getCurrentIndicatorInfo(index, event)
1625        this.currentIndex = currentIndicatorInfo.index
1626        this.setIndicatorAttr(currentIndicatorInfo.left, currentIndicatorInfo.width)
1627      })
1628
1629      Column()
1630        .height(2)
1631        .width(this.indicatorWidth)
1632        .margin({ start: LengthMetrics.vp(this.indicatorLeftMargin), top: LengthMetrics.vp(48) })
1633        .backgroundColor('#007DFF')
1634    }.width('100%')
1635  }
1636
1637  private getCurrentIndicatorInfo(index: number, event: TabsAnimationEvent): Record<string, number> {
1638    let nextIndex = index
1639    if (index > 0 && (CommonUtil.getIsRTL() ? event.currentOffset < 0 : event.currentOffset > 0)) {
1640      nextIndex--
1641    } else if (index < this.textInfos.length - 1 &&
1642        (CommonUtil.getIsRTL() ? event.currentOffset > 0 : event.currentOffset < 0)) {
1643      nextIndex++
1644    }
1645    let indexInfo = this.textInfos[index]
1646    let nextIndexInfo = this.textInfos[nextIndex]
1647    let swipeRatio = Math.abs(event.currentOffset / this.tabsWidth)
1648    let currentIndex = swipeRatio > 0.5 ? nextIndex : index // 页面滑动超过一半,tabBar切换到下一页。
1649    let currentLeft = indexInfo[0] + (nextIndexInfo[0] - indexInfo[0]) * swipeRatio
1650    let currentWidth = indexInfo[1] + (nextIndexInfo[1] - indexInfo[1]) * swipeRatio
1651    return { 'index': currentIndex, 'left': currentLeft, 'width': currentWidth }
1652  }
1653
1654  private startAnimateTo(duration: number, leftMargin: number, width: number) {
1655    this.isStartAnimateTo = true
1656    animateTo({
1657      duration: duration, // 动画时长
1658      curve: Curve.Linear, // 动画曲线
1659      iterations: 1, // 播放次数
1660      playMode: PlayMode.Normal, // 动画模式
1661      onFinish: () => {
1662        this.isStartAnimateTo = false
1663        console.info('play end')
1664      }
1665    }, () => {
1666      this.setIndicatorAttr(leftMargin, width)
1667    })
1668  }
1669
1670  private setIndicatorAttr(leftMargin: number, width: number) {
1671    this.indicatorWidth = width
1672    if (CommonUtil.getIsRTL()) {
1673      this.indicatorLeftMargin = this.tabsWidth - leftMargin - width
1674    } else {
1675      this.indicatorLeftMargin = leftMargin
1676    }
1677  }
1678}
1679```
1680
1681![tabs10](figures/tabs10.gif)
1682
1683### 示例10(预加载子节点)
1684
1685本示例通过preloadItems接口实现了预加载指定子节点。
1686
1687```ts
1688// xxx.ets
1689import { BusinessError } from '@kit.BasicServicesKit'
1690
1691@Entry
1692@Component
1693struct TabsPreloadItems {
1694  @State currentIndex: number = 1
1695  private tabsController: TabsController = new TabsController()
1696
1697  build() {
1698    Column() {
1699      Tabs({ index: this.currentIndex, controller: this.tabsController }) {
1700        TabContent() {
1701          MyComponent({ color: '#00CB87' })
1702        }.tabBar(SubTabBarStyle.of('green'))
1703
1704        TabContent() {
1705          MyComponent({ color: '#007DFF' })
1706        }.tabBar(SubTabBarStyle.of('blue'))
1707
1708        TabContent() {
1709          MyComponent({ color: '#FFBF00' })
1710        }.tabBar(SubTabBarStyle.of('yellow'))
1711
1712        TabContent() {
1713          MyComponent({ color: '#E67C92' })
1714        }.tabBar(SubTabBarStyle.of('pink'))
1715      }
1716      .width(360)
1717      .height(296)
1718      .backgroundColor('#F1F3F5')
1719      .onChange((index: number) => {
1720        this.currentIndex = index
1721      })
1722
1723      Button('preload items: [0, 2, 3]')
1724        .margin(5)
1725        .onClick(() => {
1726          // 预加载第0、2、3个子节点,提高滑动或点击切换至这些节点时的性能
1727          this.tabsController.preloadItems([0, 2, 3])
1728            .then(() => {
1729              console.info('preloadItems success.')
1730            })
1731            .catch((error: BusinessError) => {
1732              console.error('preloadItems failed, error code: ' + error.code + ', error message: ' + error.message)
1733            })
1734        })
1735    }
1736  }
1737}
1738
1739@Component
1740struct MyComponent {
1741  private color: string = ""
1742
1743  aboutToAppear(): void {
1744    console.info('aboutToAppear backgroundColor:' + this.color)
1745  }
1746
1747  aboutToDisappear(): void {
1748    console.info('aboutToDisappear backgroundColor:' + this.color)
1749  }
1750
1751  build() {
1752    Column()
1753      .width('100%')
1754      .height('100%')
1755      .backgroundColor(this.color)
1756  }
1757}
1758```
1759
1760### 示例11(设置TabBar平移距离和不透明度)
1761
1762本示例通过setTabBarTranslate、setTabBarOpacity等接口设置了TabBar的平移距离和不透明度。
1763
1764```ts
1765// xxx.ets
1766@Entry
1767@Component
1768struct TabsExample {
1769  private controller: TabsController = new TabsController()
1770
1771  build() {
1772    Column() {
1773      Button('设置TabBar的平移距离').margin({ top: 20 })
1774        .onClick(() => {
1775          this.controller.setTabBarTranslate({ x: -20, y: -20 })
1776        })
1777
1778      Button('设置TabBar的透明度').margin({ top: 20 })
1779        .onClick(() => {
1780          this.controller.setTabBarOpacity(0.5)
1781        })
1782
1783      Tabs({ barPosition: BarPosition.End, controller: this.controller }) {
1784        TabContent() {
1785          Column().width('100%').height('100%').backgroundColor('#00CB87')
1786        }.tabBar(BottomTabBarStyle.of($r('app.media.startIcon'), 'green'))
1787
1788        TabContent() {
1789          Column().width('100%').height('100%').backgroundColor('#007DFF')
1790        }.tabBar(BottomTabBarStyle.of($r('app.media.startIcon'), 'blue'))
1791
1792        TabContent() {
1793          Column().width('100%').height('100%').backgroundColor('#FFBF00')
1794        }.tabBar(BottomTabBarStyle.of($r('app.media.startIcon'), 'yellow'))
1795
1796        TabContent() {
1797          Column().width('100%').height('100%').backgroundColor('#E67C92')
1798        }.tabBar(BottomTabBarStyle.of($r('app.media.startIcon'), 'pink'))
1799      }
1800      .width(360)
1801      .height(296)
1802      .margin({ top: 20 })
1803      .barBackgroundColor('#F1F3F5')
1804    }
1805    .width('100%')
1806  }
1807}
1808```
1809
1810![tabs11](figures/tabs11.gif)
1811
1812### 示例12(页面懒加载和释放)
1813
1814本示例通过使用自定义TabBar与Swiper配合LazyForEach实现页面懒加载和释放。
1815
1816```ts
1817// xxx.ets
1818class MyDataSource implements IDataSource {
1819  private list: number[] = []
1820
1821  constructor(list: number[]) {
1822    this.list = list
1823  }
1824
1825  totalCount(): number {
1826    return this.list.length
1827  }
1828
1829  getData(index: number): number {
1830    return this.list[index]
1831  }
1832
1833  registerDataChangeListener(listener: DataChangeListener): void {
1834  }
1835
1836  unregisterDataChangeListener() {
1837  }
1838}
1839
1840@Entry
1841@Component
1842struct TabsSwiperExample {
1843  @State fontColor: string = '#182431'
1844  @State selectedFontColor: string = '#007DFF'
1845  @State currentIndex: number = 0
1846  private list: number[] = []
1847  private tabsController: TabsController = new TabsController()
1848  private swiperController: SwiperController = new SwiperController()
1849  private swiperData: MyDataSource = new MyDataSource([])
1850
1851  aboutToAppear(): void {
1852    for (let i = 0; i <= 9; i++) {
1853      this.list.push(i);
1854    }
1855    this.swiperData = new MyDataSource(this.list)
1856  }
1857
1858  @Builder tabBuilder(index: number, name: string) {
1859    Column() {
1860      Text(name)
1861        .fontColor(this.currentIndex === index ? this.selectedFontColor : this.fontColor)
1862        .fontSize(16)
1863        .fontWeight(this.currentIndex === index ? 500 : 400)
1864        .lineHeight(22)
1865        .margin({ top: 17, bottom: 7 })
1866      Divider()
1867        .strokeWidth(2)
1868        .color('#007DFF')
1869        .opacity(this.currentIndex === index ? 1 : 0)
1870    }.width('20%')
1871  }
1872
1873  build() {
1874    Column() {
1875      Tabs({ barPosition: BarPosition.Start, controller: this.tabsController }) {
1876        ForEach(this.list, (item: number) => {
1877          TabContent().tabBar(this.tabBuilder(item, '页签 ' + this.list[item]))
1878        })
1879      }
1880      .onTabBarClick((index: number) => {
1881        this.currentIndex = index
1882        this.swiperController.changeIndex(index, true)
1883      })
1884      .barMode(BarMode.Scrollable)
1885      .backgroundColor('#F1F3F5')
1886      .height(56)
1887      .width('100%')
1888
1889      Swiper(this.swiperController) {
1890        LazyForEach(this.swiperData, (item: string) => {
1891          Text(item.toString())
1892            .onAppear(()=>{
1893              console.info('onAppear ' + item.toString())
1894            })
1895            .onDisAppear(()=>{
1896              console.info('onDisAppear ' + item.toString())
1897            })
1898            .width('100%')
1899            .height('100%')
1900            .backgroundColor(0xAFEEEE)
1901            .textAlign(TextAlign.Center)
1902            .fontSize(30)
1903        }, (item: string) => item)
1904      }
1905      .loop(false)
1906      .onChange((index: number) => {
1907        this.currentIndex = index
1908      })
1909      .onAnimationStart((index: number, targetIndex: number, extraInfo: SwiperAnimationEvent) => {
1910        this.currentIndex = targetIndex
1911        this.tabsController.changeIndex(targetIndex)
1912      })
1913    }
1914  }
1915}
1916```
1917
1918![tabs12](figures/tabs12.gif)