• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Tabs
2<!--Kit: ArkUI-->
3<!--Subsystem: ArkUI-->
4<!--Owner: @CCFFWW-->
5<!--Designer: @yangfan229-->
6<!--Tester: @lxl007-->
7<!--Adviser: @HelloCrease-->
8
9通过页签进行内容视图切换的容器组件,每个页签对应一个内容视图。
10
11>  **说明:**
12>
13>  该组件从API version 7开始支持。后续版本如有新增内容,则采用上角标单独标记该内容的起始版本。
14>
15>  该组件从API version 11开始默认支持安全区避让特性(默认值为:expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.BOTTOM])),开发者可以重写该属性覆盖默认行为,API version 11之前的版本需配合[expandSafeArea](ts-universal-attributes-expand-safe-area.md)属性实现安全区避让。
16
17
18## 子组件
19
20仅支持子组件[TabContent](ts-container-tabcontent.md),以及渲染控制类型[if/else](../../../ui/state-management/arkts-rendering-control-ifelse.md)和[ForEach](../../../ui/state-management/arkts-rendering-control-foreach.md),不建议自定义组件作为子组件。并且if/else和ForEach下也仅支持TabContent作为子组件,不建议自定义组件作为子组件。
21
22>  **说明:**
23>
24>  Tabs子组件的visibility属性设置为None,或者visibility属性设置为Hidden时,对应子组件不显示,但依然会在视窗内占位。
25>
26>  Tabs子组件TabContent显示之后不会销毁,若需要页面懒加载和释放,可以参考[示例13](#示例13页面懒加载和释放)。
27>
28>  Tabs设置[height](ts-universal-attributes-size.md#height)为auto时,可根据子组件高度自适应高度大小。设置[width](ts-universal-attributes-size.md#width)为auto时,可根据子组件宽度自适应宽度大小。
29
30
31## 接口
32
33Tabs(options?: TabsOptions)
34
35创建Tabs容器。
36
37**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
38
39**系统能力:** SystemCapability.ArkUI.ArkUI.Full
40
41**参数:**
42
43| 参数名 | 类型         | 必填 | 说明 |
44| -------- | -------- | -------- | -------- |
45| options | [TabsOptions](#tabsoptions15) | 否 | Tabs组件参数。 |
46
47## TabsOptions<sup>15+</sup>
48
49Tabs组件参数,设置Tabs的页签位置,当前显示页签的索引,Tabs控制器和TabBar的[通用属性](ts-component-general-attributes.md)。
50
51**系统能力:** SystemCapability.ArkUI.ArkUI.Full
52
53| 名称         | 类型                              | 必填   | 说明                                     |
54| ----------- | --------------------------------- | ---- | ---------------------------------------- |
55| barPosition<sup>7+</sup> | [BarPosition](#barposition枚举说明)| 否    | 设置Tabs的页签位置。<br/>默认值:BarPosition.Start。<br/>**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。   |
56| index<sup>7+</sup>       | number                            | 否    | 设置当前显示页签的索引。<br/>默认值:0<br/>**说明:** <br/>设置为小于0的值时按默认值显示。<br/>可选值为[0, TabContent子节点数量-1]。<br/>直接修改index跳页时,切换动效不生效。 使用TabController的changeIndex时,默认生效切换动效,可以设置animationDuration为0关闭动画。<br />从API version 10开始,该参数支持[$$](../../../ui/state-management/arkts-two-way-sync.md)双向绑定变量。<br/>Tabs重建、系统资源切换(如系统字体切换、系统深浅色切换)或者组件属性变化时,会跳转到index对应的页面。若需要在上述情况下不跳转,建议使用双向绑定。<br/>**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 |
57| controller<sup>7+</sup>  | [TabsController](#tabscontroller) | 否    | 设置Tabs控制器。<br/>**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。         |
58| barModifier<sup>15+</sup>  | [CommonModifier](#commonmodifier15) | 否    | 设置TabBar的[通用属性](ts-component-general-attributes.md)。<br/>**说明:** <br/>动态置为undefined时会保持当前状态不变,不会重置各通用属性。 <br/>由一个CommonModifier切换为另一个CommonModifier时,重复属性会进行覆盖,非重复属性会同时生效,不会重置前一个CommonModifier的通用属性。<br/>Tabs的[barWidth](#barwidth)、[barHeight](#barheight)、[barBackgroundColor](#barbackgroundcolor10)、[barBackgroundBlurStyle](#barbackgroundblurstyle18)、[barBackgroundEffect](#barbackgroundeffect18)属性会覆盖CommonModifier的[width](ts-universal-attributes-size.md#width)、[height](ts-universal-attributes-size.md#height)、[backgroundColor](ts-universal-attributes-background.md#backgroundcolor18)、[backgroundBlurStyle](ts-universal-attributes-background.md#backgroundblurstyle18)、[backgroundEffect](ts-universal-attributes-background.md#backgroundeffect18)属性。<br/>[align](ts-universal-attributes-location.md#align)属性仅在[BarMode.Scrollable](#barmode10-1)模式下生效,且Tabs为横向时还需[nonScrollableLayoutStyle](#scrollablebarmodeoptions10对象说明)未设置或设置为异常值时才能生效。<br/>[TabContent](ts-container-tabcontent.md)组件的[tabBar](ts-container-tabcontent.md#tabbar18)属性为底部页签样式时不支持拖拽功能。<br/>**原子化服务API:** 从API version 15开始,该接口支持在原子化服务中使用。|
59
60## BarPosition枚举说明
61
62Tabs页签位置枚举。
63
64**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
65
66**系统能力:** SystemCapability.ArkUI.ArkUI.Full
67
68| 名称  | 说明                                                         |
69| ----- | ------------------------------------------------------------ |
70| Start | vertical属性方法设置为true时,页签位于容器左侧;vertical属性方法设置为false时,页签位于容器顶部。 |
71| End   | vertical属性方法设置为true时,页签位于容器右侧;vertical属性方法设置为false时,页签位于容器底部。 |
72
73
74## 属性
75
76除支持[通用属性](ts-component-general-attributes.md)外,还支持以下属性:
77
78### vertical
79
80vertical(value: boolean)
81
82设置是否为纵向Tab。
83
84**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
85
86**系统能力:** SystemCapability.ArkUI.ArkUI.Full
87
88**参数:**
89
90| 参数名 | 类型    | 必填 | 说明                                                         |
91| ------ | ------- | ---- | ------------------------------------------------------------ |
92| 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/>尽量保持每一个页面中的子组件尺寸大小一致,避免滑动页面时出现页面切换动画跳动现象。 |
93
94### scrollable
95
96scrollable(value: boolean)
97
98设置是否可以通过滑动页面进行页面切换。
99
100**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
101
102**系统能力:** SystemCapability.ArkUI.ArkUI.Full
103
104**参数:**
105
106| 参数名 | 类型    | 必填 | 说明                                                         |
107| ------ | ------- | ---- | ------------------------------------------------------------ |
108| value  | boolean | 是   | 是否可以通过滑动页面进行页面切换。<br/>默认值:true,可以通过滑动页面进行页面切换。为false时不可滑动切换页面。 |
109
110### barMode
111
112barMode(value: BarMode, options?: ScrollableBarModeOptions)
113
114设置TabBar布局模式。
115
116**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
117
118**系统能力:** SystemCapability.ArkUI.ArkUI.Full
119
120**参数:**
121
122| 参数名                | 类型                                                         | 必填 | 说明                                                         |
123| --------------------- | ------------------------------------------------------------ | ---- | ------------------------------------------------------------ |
124| value                 | [BarMode](#barmode枚举说明)                                  | 是   | 布局模式。<br/>默认值:BarMode.Fixed                                                 |
125| options<sup>10+</sup> | [ScrollableBarModeOptions](#scrollablebarmodeoptions10对象说明) | 否   | Scrollable模式下的TabBar的布局样式。<br/>**说明:** <br/>仅Scrollable且水平模式下有效。 |
126
127### barMode<sup>10+</sup>
128
129barMode(value: BarMode.Fixed)
130
131设置TabBar布局模式为BarMode.Fixed132
133**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
134
135**系统能力:** SystemCapability.ArkUI.ArkUI.Full
136
137**参数:**
138
139| 参数名    | 类型                             | 必填 | 说明                                    |
140| -------- | -------------------------------- | ---- | ------------------------------------ |
141| value    | [BarMode.Fixed](#barmode枚举说明) | 是   | 所有TabBar会平均分配barWidth宽度(纵向时平均分配barHeight高度)。   |
142
143### barMode<sup>10+</sup>
144
145barMode(value: BarMode.Scrollable, options: ScrollableBarModeOptions)
146
147设置TabBar布局模式为BarMode.Scrollable148
149**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
150
151**系统能力:** SystemCapability.ArkUI.ArkUI.Full
152
153**参数:**
154
155| 参数名    | 类型                              | 必填 | 说明                                    |
156| -------- | --------------------------------- | ---- | ------------------------------------- |
157| value    | [BarMode.Scrollable](#barmode枚举说明) | 是   | 所有TabBar都使用实际布局宽度,超过总宽度(横向Tabs的barWidth,纵向Tabs的barHeight)后可滑动。        |
158| options | [ScrollableBarModeOptions](#scrollablebarmodeoptions10对象说明) | 是   | Scrollable模式下的TabBar的布局样式。<br/>**说明:** <br/>仅水平模式下有效。  |
159
160### barWidth
161
162barWidth(value: Length)
163
164设置TabBar的宽度值。设置为小于0或大于Tabs宽度值时,按默认值显示。
165
166**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
167
168**系统能力:** SystemCapability.ArkUI.ArkUI.Full
169
170**参数:**
171
172| 参数名 | 类型                                      | 必填 | 说明                                                         |
173| ------ | ----------------------------------------- | ---- | ------------------------------------------------------------ |
174| 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的宽度。 |
175
176### barHeight
177
178barHeight(value: Length)
179
180设置TabBar的高度值。横向Tabs可以设置height为'auto',让TabBar自适应子组件高度。height设置为小于0或大于Tabs高度值时,按默认值显示。
181
182API version 14之前的版本,若设置barHeight为固定值后,TabBar无法扩展底部安全区。从API version 14开始支持配合[safeAreaPadding](./ts-universal-attributes-size.md#safeareapadding14)属性,当safeAreaPadding不设置bottom或者bottom设置为0时,可以实现扩展安全区。
183
184**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
185
186**系统能力:** SystemCapability.ArkUI.ArkUI.Full
187
188**参数:**
189
190| 参数名 | 类型                                      | 必填 | 说明                                                         |
191| ------ | ----------------------------------------- | ---- | ------------------------------------------------------------ |
192| value  | [Length](ts-types.md#length)<sup>8+</sup> | 是   | TabBar的高度值。<br/>默认值:<br/>未设置样式或者通过CustomBuilder设置自定义样式的TabBar且vertical属性为false时,默认值为56vp。<br/>未设置样式或者通过CustomBuilder设置自定义样式的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。 |
193
194### barHeight<sup>20+</sup>
195
196barHeight(height: Length, noMinHeightLimit: boolean)
197
198设置TabBar的高度值。横向Tabs可以设置height为'auto',让TabBar自适应子组件高度,并通过设置noMinHeightLimit为true让自适应高度可以小于TabBar默认高度。height设置为小于0或大于Tabs高度值时,按默认值显示。
199
200**原子化服务API:** 从API version 20开始,该接口支持在原子化服务中使用。
201
202**系统能力:** SystemCapability.ArkUI.ArkUI.Full
203
204**参数:**
205
206| 参数名           | 类型                         | 必填 | 说明                                                         |
207| ---------------- | ---------------------------- | ---- | ------------------------------------------------------------ |
208| height           | [Length](ts-types.md#length) | 是   | TabBar的高度值。<br/>默认值:<br/>未设置样式或者通过CustomBuilder设置自定义样式的TabBar且vertical属性为false时,默认值为56vp。<br/>未设置样式或者通过CustomBuilder设置自定义样式的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时,默认值为48vp。 |
209| noMinHeightLimit | boolean                      | 是   | height设置为'auto'时,设置是否取消TabBar的最小高度限制。默认值为false。<br/>**说明:** <br/>值为true表示取消TabBar的最小高度限制,即TabBar的高度值可以小于默认值。<br/>值为false表示限制TabBar的最小高度,即TabBar的最小高度值等于默认值。 |
210
211### animationCurve<sup>20+</sup>
212
213animationCurve(curve: Curve | ICurve)
214
215设置Tabs翻页动画曲线。常用曲线参考[Curve](ts-appendix-enums.md#curve)枚举说明,也可以通过[插值计算](../js-apis-curve.md)模块提供的接口创建自定义的插值曲线对象。
216
217**原子化服务API:** 从API version 20开始,该接口支持在原子化服务中使用。
218
219**系统能力:** SystemCapability.ArkUI.ArkUI.Full
220
221**参数:**
222
223| 参数名 | 类型                                                         | 必填 | 说明                                        |
224| ------ | ------------------------------------------------------------ | ---- | ------------------------------------------- |
225| curve  | [Curve](ts-appendix-enums.md#curve)&nbsp;\|&nbsp;[ICurve](../js-apis-curve.md#icurve9) | 是   | Tabs翻页的动画曲线。<br/>默认值:<br/>滑动TabContent翻页时,默认值为interpolatingSpring(-1, 1, 228, 30)。<br/>点击TabBar页签和调用TabsController的changeIndex接口翻页时,默认值为cubicBezierCurve(0.2, 0.0, 0.1, 1.0)。<br/>设置自定义动画曲线时,滑动翻页和点击页签、调用changeIndex翻页都使用设置的动画曲线。 |
226
227### animationDuration
228
229animationDuration(value: number)
230
231设置Tabs翻页动画时长。
232
233animationCurve不设置时,由于滑动TabContent翻页动画曲线interpolatingSpring(-1, 1, 228, 30)时长只受曲线自身参数影响,animationDuration只能控制点击TabBar页签和调用TabsController的changeIndex接口切换TabContent的动画时长。
234
235不受animationDuration控制的曲线可以查阅[插值计算](../js-apis-curve.md)模块,比如[springMotion](../js-apis-curve.md#curvesspringmotion9)、[responsiveSpringMotion](../js-apis-curve.md#curvesresponsivespringmotion9)和[interpolatingSpring](../js-apis-curve.md#curvesinterpolatingspring10)类型的曲线。
236
237**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
238
239**系统能力:** SystemCapability.ArkUI.ArkUI.Full
240
241**参数:**
242
243| 参数名 | 类型   | 必填 | 说明                                                         |
244| ------ | ------ | ---- | ------------------------------------------------------------ |
245| value  | number | 是   | Tabs翻页的动画时长。<br/>默认值:<br/>API version 10及以前,不设置该属性或设置为null时,默认值为0,即Tabs翻页无动画。设置为小于0或undefined时,默认值为300。<br/>API version 11及以后,不设置该属性或设置为异常值,且设置TabBar为BottomTabBarStyle样式时,默认值为0。设置TabBar为其他样式时,默认值为300。<br/>单位:ms<br/>取值范围:[0, +∞) |
246
247### animationMode<sup>12+</sup>
248
249animationMode(mode: Optional\<AnimationMode\>)
250
251设置点击TabBar页签或调用TabsController的changeIndex接口时切换TabContent的动画形式。
252
253**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
254
255**系统能力:** SystemCapability.ArkUI.ArkUI.Full
256
257**参数:**
258
259| 参数名 | 类型   | 必填 | 说明                                                         |
260| ------ | ------ | ---- | ------------------------------------------------------------ |
261| mode  | Optional\<[AnimationMode](#animationmode12枚举说明)\> | 是   | 点击TabBar页签或调用TabsController的changeIndex接口时切换TabContent的动画形式。<br/>默认值:AnimationMode.CONTENT_FIRST,表示在点击TabBar页签或调用TabsController的changeIndex接口切换TabContent时,先加载目标页内容,再开始切换动画。|
262
263### barPosition<sup>9+</sup>
264
265barPosition(value: BarPosition)
266
267设置Tabs的页签位置。
268
269**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
270
271**系统能力:** SystemCapability.ArkUI.ArkUI.Full
272
273**参数:**
274
275| 参数名 | 类型                               | 必填 | 说明                  |
276| ----- | ---------------------------------- | ---- | -------------------- |
277| value | [BarPosition](#barposition枚举说明)| 是  | 设置Tabs的页签位置。<br/>默认值:BarPosition.Start   |
278
279### divider<sup>10+</sup>
280
281divider(value: DividerStyle | null)
282
283设置区分TabBar和TabContent的分割线样式。
284
285**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
286
287**系统能力:** SystemCapability.ArkUI.ArkUI.Full
288
289**参数:**
290
291| 参数名 | 类型                                                      | 必填 | 说明                                                         |
292| ------ | --------------------------------------------------------- | ---- | ------------------------------------------------------------ |
293| value  | [DividerStyle](#dividerstyle10对象说明)&nbsp;\|&nbsp;null | 是   | 分割线样式,默认不显示分割线。<br/>DividerStyle:分割线的样式;<br/>null:不显示分割线。 |
294
295### fadingEdge<sup>10+</sup>
296
297fadingEdge(value: boolean)
298
299设置页签超过容器宽度时是否渐隐消失。建议配合barBackgroundColor属性一起使用,如果barBackgroundColor属性没有定义,会默认显示页签末端为白色的渐隐效果。
300
301**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
302
303**系统能力:** SystemCapability.ArkUI.ArkUI.Full
304
305**参数:**
306
307| 参数名 | 类型    | 必填 | 说明                                               |
308| ------ | ------- | ---- | -------------------------------------------------- |
309| value  | boolean | 是   | 页签超过容器宽度时是否渐隐消失。<br />默认值:true,页签超过容器宽度时会渐隐消失。设置为false时,页签超过容器宽度直接截断显示,不产生任何渐变效果‌。 |
310
311### barOverlap<sup>10+</sup>
312
313barOverlap(value: boolean)
314
315设置TabBar是否背后变模糊并叠加在TabContent之上。
316
317**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
318
319**系统能力:** SystemCapability.ArkUI.ArkUI.Full
320
321**参数:**
322
323| 参数名 | 类型    | 必填 | 说明                                                         |
324| ------ | ------- | ---- | ------------------------------------------------------------ |
325| value  | boolean | 是   | TabBar是否背后变模糊并叠加在TabContent之上。当barOverlap设置为true时,TabBar背后变模糊并叠加在TabContent之上,并且TabBar默认模糊材质的BlurStyle值修改为'BlurStyle.COMPONENT_THICK'。当barOverlap设置为false时,无模糊和叠加效果。<br />默认值:false |
326
327### barBackgroundColor<sup>10+</sup>
328
329barBackgroundColor(value: ResourceColor)
330
331设置TabBar的背景颜色。
332
333**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
334
335**系统能力:** SystemCapability.ArkUI.ArkUI.Full
336
337**参数:**
338
339| 参数名 | 类型                                       | 必填 | 说明                                 |
340| ------ | ------------------------------------------ | ---- | ------------------------------------ |
341| value  | [ResourceColor](ts-types.md#resourcecolor) | 是   | TabBar的背景颜色。<br />默认值:Color.Transparent,透明 |
342
343### barBackgroundBlurStyle<sup>11+</sup>
344
345barBackgroundBlurStyle(value: BlurStyle)
346
347设置TabBar的背景模糊材质。
348
349**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
350
351**系统能力:** SystemCapability.ArkUI.ArkUI.Full
352
353**参数:**
354
355| 参数名 | 类型                                         | 必填 | 说明                                     |
356| ------ | -------------------------------------------- | ---- | ---------------------------------------- |
357| value  | [BlurStyle](ts-universal-attributes-background.md#blurstyle9) | 是   | TabBar的背景模糊材质。<br />默认值:BlurStyle.NONE |
358
359### barBackgroundBlurStyle<sup>18+</sup>
360
361barBackgroundBlurStyle(style: BlurStyle, options: BackgroundBlurStyleOptions)
362
363为TabBar提供一种在背景和内容之间的模糊能力,通过枚举值的方式封装了不同的模糊半径、蒙版颜色、蒙版透明度、饱和度、亮度。
364
365**原子化服务API:** 从API version 18开始,该接口支持在原子化服务中使用。
366
367**系统能力:** SystemCapability.ArkUI.ArkUI.Full
368
369**参数:**
370
371| 参数名                | 类型                                                         | 必填 | 说明                                                         |
372| --------------------- | ------------------------------------------------------------ | ---- | ------------------------------------------------------------ |
373| style                 | [BlurStyle](ts-universal-attributes-background.md#blurstyle9)                 | 是   | 背景模糊样式。模糊样式中封装了模糊半径、蒙版颜色、蒙版透明度、饱和度、亮度五个参数。 |
374| options | [BackgroundBlurStyleOptions](ts-universal-attributes-background.md#backgroundblurstyleoptions10对象说明) | 是   | 背景模糊选项。
375
376### barGridAlign<sup>10+</sup>
377
378barGridAlign(value: BarGridColumnOptions)
379
380以栅格化方式设置TabBar的可见区域。具体参见BarGridColumnOptions对象。仅水平模式下有效,[不适用于XS、XL和XXL设备](../../../ui/arkts-layout-development-grid-layout.md#栅格容器断点)。
381
382**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
383
384**系统能力:** SystemCapability.ArkUI.ArkUI.Full
385
386**参数:**
387
388| 参数名 | 类型                                                    | 必填 | 说明                               |
389| ------ | ------------------------------------------------------- | ---- | ---------------------------------- |
390| value  | [BarGridColumnOptions](#bargridcolumnoptions10对象说明) | 是   | 以栅格化方式设置TabBar的可见区域。 |
391
392### edgeEffect<sup>12+</sup>
393
394edgeEffect(edgeEffect: Optional&lt;EdgeEffect&gt;)
395
396设置边缘回弹效果。
397
398**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
399
400**系统能力:** SystemCapability.ArkUI.ArkUI.Full
401
402**参数:**
403
404| 参数名 | 类型                                          | 必填 | 说明                                         |
405| ------ | --------------------------------------------- | ---- | -------------------------------------------- |
406| edgeEffect  | Optional&lt;[EdgeEffect](ts-appendix-enums.md#edgeeffect)&gt; | 是   | 边缘滑动效果。<br/>默认值:EdgeEffect.Spring |
407
408### barBackgroundEffect<sup>18+</sup>
409
410barBackgroundEffect(options: BackgroundEffectOptions)
411
412设置TabBar背景属性,包含背景模糊半径,亮度,饱和度,颜色等参数。
413
414**原子化服务API:** 从API version 18开始,该接口支持在原子化服务中使用。
415
416**系统能力:** SystemCapability.ArkUI.ArkUI.Full
417
418**参数:**
419
420| 参数名  | 类型                                                         | 必填 | 说明                                       |
421| ------- | ------------------------------------------------------------ | ---- | ------------------------------------------ |
422| options | [BackgroundEffectOptions](ts-universal-attributes-background.md#backgroundeffectoptions11) | 是   | 设置TabBar背景属性包括:模糊半径,亮度,饱和度,颜色等。 |
423
424### pageFlipMode<sup>15+</sup>
425
426pageFlipMode(mode: Optional\<PageFlipMode>)
427
428设置鼠标滚轮翻页模式。
429
430**原子化服务API:** 从API version 15开始,该接口支持在原子化服务中使用。
431
432**系统能力:** SystemCapability.ArkUI.ArkUI.Full
433
434**参数:**
435
436| 参数名 | 类型                                                        | 必填 | 说明                                                         |
437| ------ | ----------------------------------------------------------- | ---- | ------------------------------------------------------------ |
438| mode  | Optional\<[PageFlipMode](ts-appendix-enums.md#pageflipmode15)> | 是   | 鼠标滚轮翻页模式。<br/>默认值:PageFlipMode.CONTINUOUS |
439
440### cachedMaxCount<sup>19+</sup>
441
442cachedMaxCount(count: number, mode: TabsCacheMode)
443
444设置子组件的最大缓存个数和缓存模式。设置该属性后,不会对缓存范围内的子组件进行预加载,仅对缓存范围外的子组件进行释放。
445
446**原子化服务API:** 从API version 19开始,该接口支持在原子化服务中使用。
447
448**系统能力:** SystemCapability.ArkUI.ArkUI.Full
449
450**参数:**
451
452| 参数名 | 类型                                                        | 必填 | 说明                                                         |
453| ------ | ----------------------------------------------------------- | ---- | ------------------------------------------------------------ |
454| count  | number                                                      | 是   | 子组件的最大缓存个数。默认所有子组件加载后都不再释放。<br/>取值范围:[0, +∞)。|
455| mode   | [TabsCacheMode](#tabscachemode19枚举说明)                   | 是   | 子组件的缓存模式。<br/>默认值:TabsCacheMode.CACHE_BOTH_SIDE   |
456
457## DividerStyle<sup>10+</sup>对象说明
458
459分割线样式对象。
460
461**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
462
463**系统能力:** SystemCapability.ArkUI.ArkUI.Full
464
465| 名称          | 类型                                     | 必填   | 说明                                       |
466| ----------- | ---------------------------------------- | ---- | ---------------------------------------- |
467| strokeWidth | [Length](ts-types.md#length)             | 是    | 分割线的线宽(不支持百分比设置)。<br/>默认值:0.0<br/>单位:vp<br/>取值范围:[0, +∞)。           |
468| color       | [ResourceColor](ts-types.md#resourcecolor) | 否    | 分割线的颜色。<br/>默认值:#33182431                |
469| startMargin | [Length](ts-types.md#length)             | 否    | 分割线与侧边栏顶端的距离(不支持百分比设置)。<br/>默认值:0.0<br/>单位:vp<br/>取值范围:[0, +∞)。 |
470| endMargin   | [Length](ts-types.md#length)             | 否    | 分割线与侧边栏底端的距离(不支持百分比设置)。<br/>默认值:0.0<br/>单位:vp<br/>取值范围:[0, +∞)。 |
471
472## BarGridColumnOptions<sup>10+</sup>对象说明
473
474TabBar栅格化方式设置的对象,包括栅格模式下的column边距和间隔,以及小、中、大屏下,页签占用的columns数量。
475
476**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
477
478**系统能力:** SystemCapability.ArkUI.ArkUI.Full
479
480| 名称          | 类型                                     | 必填   | 说明                                       |
481| ----------- | ---------------------------------------- | ---- | ---------------------------------------- |
482| margin | [Dimension](ts-types.md#dimension10)             | 否    | 栅格模式下的column边距(不支持百分比设置)。<br/>默认值:24.0<br/>单位:vp                        |
483| gutter      | [Dimension](ts-types.md#dimension10) | 否    | 栅格模式下的column间隔(不支持百分比设置)。<br/>默认值:24.0<br/>单位:vp                     |
484| sm | number            | 否    | 小屏下,页签占用的columns数量,必须是非负偶数。小屏为大于等于320vp但小于600vp。<br/>默认值为-1,代表页签占用TabBar全部宽度。 |
485| md   | number          | 否    | 中屏下,页签占用的columns数量,必须是非负偶数。中屏为大于等于600vp但小于800vp。<br/>默认值为-1,代表页签占用TabBar全部宽度。 |
486| lg   | number           | 否    | 大屏下,页签占用的columns数量,必须是非负偶数。大屏为大于等于840vp但小于1024vp。<br/>默认值为-1,代表页签占用TabBar全部宽度。 |
487
488## ScrollableBarModeOptions<sup>10+</sup>对象说明
489
490Scrollable模式下的TabBar的布局样式对象。
491
492**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
493
494**系统能力:** SystemCapability.ArkUI.ArkUI.Full
495
496| 名称          | 类型                                     | 必填   | 说明                                       |
497| ----------- | ---------------------------------------- | ---- | ---------------------------------------- |
498| margin | [Dimension](ts-types.md#dimension10)          | 否    | Scrollable模式下的TabBar的左右边距(不支持百分比设置)。<br/>默认值:0.0<br/>单位:vp<br/>取值范围:[0, +∞)。|
499| nonScrollableLayoutStyle      | [LayoutStyle](#layoutstyle10枚举说明) | 否    | Scrollable模式下不滚动时的页签排布方式。<br/>默认值:LayoutStyle.ALWAYS_CENTER           |
500
501## BarMode枚举说明
502
503TabBar布局模式枚举。
504
505**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
506
507**系统能力:** SystemCapability.ArkUI.ArkUI.Full
508
509| 名称        | 值 | 说明                                     |
510| ---------- | -- | ---------------------------------------- |
511| Scrollable | 0  | 每一个TabBar均使用实际布局宽度,超过总长度(横向Tabs的barWidth,纵向Tabs的barHeight)后可滑动。 |
512| Fixed      | 1  | 所有TabBar平均分配barWidth宽度(纵向时平均分配barHeight高度)。 |
513
514## AnimationMode<sup>12+</sup>枚举说明
515
516点击TabBar页签时切换TabContent的动画形式枚举。
517
518**系统能力:** SystemCapability.ArkUI.ArkUI.Full
519
520| 名称          | 值   | 说明                                                         |
521| ------------- | ---- | ------------------------------------------------------------ |
522| CONTENT_FIRST | 0    | 先加载目标页内容,再开始切换动画。<br/>**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。|
523| ACTION_FIRST  | 1    | 先开始切换动画,再加载目标页内容;生效需要同时需要满足:Tabs的height、width没有设置成auto。<br/>**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 |
524| NO_ANIMATION  | 2    | 关闭默认动画。调用TabsController的changeIndex接口切换TabContent时该枚举值不生效。<br>可以通过设置animationDuration为0实现调用TabsController的changeIndex接口时不带动画。<br/>**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。|
525| CONTENT_FIRST_WITH_JUMP<sup>15+</sup> | 3    | 先加载目标页内容,再无动画跳转到目标页附近,最后有动画跳转到目标页。<br/>**原子化服务API:** 从API version 15开始,该接口支持在原子化服务中使用。|
526| ACTION_FIRST_WITH_JUMP<sup>15+</sup>  | 4    | 先无动画跳转到目标页附近,再有动画跳转到目标页,最后加载目标页内容。此项生效需要同时需要满足:Tabs的height、width没有设置成auto。<br/>**原子化服务API:** 从API version 15开始,该接口支持在原子化服务中使用。 |
527
528## LayoutStyle<sup>10+</sup>枚举说明
529
530Scrollable模式下不滚动时的页签排布方式枚举。
531
532**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
533
534**系统能力:** SystemCapability.ArkUI.ArkUI.Full
535
536| 名称         | 值 | 说明                                     |
537| ---------- | -- | ---------------------------------------- |
538| ALWAYS_CENTER | 0 | 当页签内容超过TabBar宽度时,TabBar可滚动。<br/>当页签内容不超过TabBar宽度时,TabBar不可滚动,页签紧凑居中。|
539| ALWAYS_AVERAGE_SPLIT | 1 | 当页签内容超过TabBar宽度时,TabBar可滚动。<br/>当页签内容不超过TabBar宽度时,TabBar不可滚动,且所有页签平均分配TabBar宽度。|
540| SPACE_BETWEEN_OR_CENTER      | 2 | 当页签内容超过TabBar宽度时,TabBar可滚动。<br/>当页签内容不超过TabBar宽度但超过TabBar宽度一半时,TabBar不可滚动,页签紧凑居中。<br/>当页签内容不超过TabBar宽度一半时,TabBar不可滚动,保证页签居中排列在TabBar宽度一半,且间距相同。|
541
542## CommonModifier<sup>15+</sup>
543
544type CommonModifier = CommonModifier
545
546作为Tabs组件的参数对象。
547
548**原子化服务API:** 从API version 15开始,该接口支持在原子化服务中使用。
549
550**系统能力:** SystemCapability.ArkUI.ArkUI.Full
551
552| 类型         | 说明                                     |
553| ---------- | ---------------------------------------- |
554| [CommonModifier](ts-universal-attributes-attribute-modifier.md#attributemodifier) | 设置TabBar的通用属性。 |
555
556## TabsCacheMode<sup>19+</sup>枚举说明
557
558子组件的缓存模式。
559
560**原子化服务API:** 从API version 19开始,该接口支持在原子化服务中使用。
561
562**系统能力:** SystemCapability.ArkUI.ArkUI.Full
563
564| 名称                  | 值 | 说明                                     |
565| --------------------- | -- | ---------------------------------------- |
566| CACHE_BOTH_SIDE       | 0  | 缓存当前显示的子组件和其两侧的子组件。即当设置cachedMaxCount属性的count值为n时,最多缓存2n+1个子组件。 |
567| CACHE_LATEST_SWITCHED | 1  | 缓存当前显示的子组件和最近切换过的子组件。即当设置cachedMaxCount属性的count值为n时,最多缓存n+1个子组件。 |
568
569## 事件
570
571除支持[通用事件](ts-component-general-events.md)外,还支持以下事件:
572
573### onChange
574
575onChange(event: Callback\<number>)
576
577Tab页签切换后触发的事件。
578
579满足以下任一条件,即可触发该事件:
580
5811、滑动页面进行页面切换时,组件滑动动画结束后触发。
582
5832、通过[控制器](#tabscontroller)调用[changeIndex](#changeindex)接口,Tab页签切换后触发。
584
5853、动态修改[状态变量](../../../ui/state-management/arkts-state.md)构造的index属性值,Tab页签切换后触发。
586
5874、点击TabBar页签,Tab页签切换后触发。
588
589>  **说明:**
590>
591>  使用自定义页签时,在onChange事件中联动可能会导致滑动页面切换后才执行页签联动,引起自定义页签切换效果延迟。建议在[onAnimationStart](#onanimationstart11)中监听并刷新当前索引,以确保动效能够及时触发。具体实现可参考[示例3](#示例3自定义页签切换联动)。
592
593**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
594
595**系统能力:** SystemCapability.ArkUI.ArkUI.Full
596
597**参数:**
598
599| 参数名 | 类型   | 必填 | 说明                                   |
600| ------ | ------ | ---- | -------------------------------------- |
601| event  | [Callback](./ts-types.md#callback12)\<number> | 是   | 当前显示的index索引,索引从0开始计算。 |
602
603### onTabBarClick<sup>10+</sup>
604
605onTabBarClick(event: Callback\<number>)
606
607Tab页签点击后触发的事件。
608
609**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
610
611**系统能力:** SystemCapability.ArkUI.ArkUI.Full
612
613**参数:**
614
615| 参数名 | 类型   | 必填 | 说明                                 |
616| ------ | ------ | ---- | ------------------------------------ |
617| event  | [Callback](./ts-types.md#callback12)\<number> | 是   | 被点击的index索引,索引从0开始计算。 |
618
619### onAnimationStart<sup>11+</sup>
620
621onAnimationStart(handler: OnTabsAnimationStartCallback)
622
623切换动画开始时触发该回调。当[animationDuration](#animationduration)为0时动画关闭且[scrollable](#scrollable)为false时,不触发该回调。
624
625**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
626
627**系统能力:** SystemCapability.ArkUI.ArkUI.Full
628
629**参数:**
630
631| 参数名 | 类型   | 必填 | 说明                 |
632| ------ | ------ | ---- | -------------------- |
633| handler  | [OnTabsAnimationStartCallback](#ontabsanimationstartcallback18) | 是   | 切换动画开始时触发的回调。 |
634
635### onAnimationEnd<sup>11+</sup>
636
637onAnimationEnd(handler: OnTabsAnimationEndCallback)
638
639切换动画结束时触发该回调,包括动画过程中手势中断。当animationDuration为0时动画关闭,不触发该回调。
640
641**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
642
643**系统能力:** SystemCapability.ArkUI.ArkUI.Full
644
645**参数:**
646
647| 参数名 | 类型   | 必填 | 说明                 |
648| ------ | ------ | ---- | -------------------- |
649| handler  | [OnTabsAnimationEndCallback](#ontabsanimationendcallback18) | 是   | 切换动画结束时触发的回调。 |
650
651### onGestureSwipe<sup>11+</sup>
652
653onGestureSwipe(handler: OnTabsGestureSwipeCallback)
654
655在页面跟手滑动过程中,逐帧触发该回调。
656
657**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
658
659**系统能力:** SystemCapability.ArkUI.ArkUI.Full
660
661**参数:**
662
663| 参数名 | 类型   | 必填 | 说明                 |
664| ------ | ------ | ---- | -------------------- |
665| handler  | [OnTabsGestureSwipeCallback](#ontabsgestureswipecallback18) | 是   | 在页面跟手滑动过程中,逐帧触发的回调。 |
666
667### customContentTransition<sup>11+</sup>
668
669customContentTransition(delegate: TabsCustomContentTransitionCallback)
670
671自定义Tabs页面切换动画。
672
673使用说明:
674
6751、当使用自定义切换动画时,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属性,来控制页面的渲染层级。
676
677**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
678
679**系统能力:** SystemCapability.ArkUI.ArkUI.Full
680
681**参数:**
682
683| 参数名 | 类型   | 必填 | 说明                 |
684| ------ | ------ | ---- | -------------------- |
685| delegate  | [TabsCustomContentTransitionCallback](#tabscustomcontenttransitioncallback18) | 是   | 自定义Tabs页面切换动画开始时触发的回调。 |
686
687
688### onContentWillChange<sup>12+</sup>
689
690onContentWillChange(handler: OnTabsContentWillChangeCallback)
691
692自定义Tabs页面切换拦截事件能力,新页面即将显示时触发该回调。
693
694满足以下任一条件,即可触发该事件:
695
6961、滑动TabContent切换新页面时触发。
697
6982、通过TabsController.changeIndex接口切换新页面时触发。
699
7003、通过动态修改index属性值切换新页面时触发。
701
7024、通过点击TabBar页签切换新页面时触发。
703
7045、TabBar页签获焦后,通过键盘左右方向键等切换新页面时触发。
705
706**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
707
708**系统能力:** SystemCapability.ArkUI.ArkUI.Full
709
710**参数:**
711
712| 参数名 | 类型   | 必填 | 说明                 |
713| ------ | ------ | ---- | -------------------- |
714| handler  | [OnTabsContentWillChangeCallback](#ontabscontentwillchangecallback18) | 是   | 自定义Tabs页面切换拦截事件能力,新页面即将显示时触发的回调。 |
715
716### onSelected<sup>18+</sup>
717
718onSelected(event: Callback\<number>)
719
720当选中元素改变时触发该回调,返回值为当前选中的元素的索引值。
721
722满足以下任一条件,即可触发该事件:
723
7241. 滑动离手时满足翻页阈值,开始切换动画时触发。
725
7262. 通过[TabsController控制器](#tabscontroller)调用[changeIndex](#changeindex)接口,开始切换动画时触发。
727
7283. 动态修改[状态变量](../../../ui/state-management/arkts-state.md)构造的index属性值后触发。
729
7304. 通过页签处点击触发。
731
732**原子化服务API:** 从API version 18开始,该接口支持在原子化服务中使用。
733
734**系统能力:** SystemCapability.ArkUI.ArkUI.Full
735
736**参数:**
737
738| 参数名 | 类型   | 必填 | 说明                                   |
739| ------ | ------ | ---- | -------------------------------------- |
740| event  | [Callback](./ts-types.md#callback12)\<number> | 是   | 当前选中元素的索引。 |
741
742> **说明:**
743>
744> onSelected回调中不可通过TabsOptions的index设置当前显示页的索引,不可调用TabsController.changeIndex()方法。
745
746### onUnselected<sup>18+</sup>
747
748onUnselected(event: Callback\<number>)
749
750当选中元素改变时触发该回调,返回值为将要隐藏的元素的索引值。
751
752满足以下任一条件,即可触发该事件:
753
7541. 滑动离手时满足翻页阈值,开始切换动画时触发。
755
7562. 通过[TabsController控制器](#tabscontroller)调用[changeIndex](#changeindex)接口,开始切换动画时触发。
757
7583. 动态修改[状态变量](../../../ui/state-management/arkts-state.md)构造的index属性值后触发。
759
7604. 通过页签处点击触发。
761
762**原子化服务API:** 从API version 18开始,该接口支持在原子化服务中使用。
763
764**系统能力:** SystemCapability.ArkUI.ArkUI.Full
765
766**参数:**
767
768| 参数名 | 类型   | 必填 | 说明                                   |
769| ------ | ------ | ---- | -------------------------------------- |
770| event  | [Callback](./ts-types.md#callback12)\<number> | 是   | 将要隐藏元素的索引。 |
771
772> **说明:**
773>
774> onUnselected回调中不可通过TabsOptions的index设置当前显示页的索引,不可调用TabsController.changeIndex()方法。
775
776## OnTabsAnimationStartCallback<sup>18+</sup>
777
778type OnTabsAnimationStartCallback = (index: number, targetIndex: number, extraInfo: TabsAnimationEvent) => void
779
780切换动画开始时触发的回调。
781
782**原子化服务API:** 从API version 18开始,该接口支持在原子化服务中使用。
783
784**系统能力:** SystemCapability.ArkUI.ArkUI.Full
785
786**参数:**
787
788| 参数名      | 类型                                                   | 必填 | 说明                                                         |
789| ----------- | ------------------------------------------------------ | ---- | ------------------------------------------------------------ |
790| index       | number                                                 | 是   | 当前显示元素的索引,索引从0开始。                             |
791| targetIndex | number                                                 | 是   | 切换动画目标元素的索引,索引从0开始。                         |
792| extraInfo       | [TabsAnimationEvent](#tabsanimationevent11对象说明) | 是   | 动画相关信息,包括主轴方向上当前显示元素和目标元素相对Tabs起始位置的位移,以及离手速度。 |
793
794## OnTabsAnimationEndCallback<sup>18+</sup>
795
796type OnTabsAnimationEndCallback = (index: number, extraInfo: TabsAnimationEvent) => void
797
798切换动画结束时触发的回调。
799
800**原子化服务API:** 从API version 18开始,该接口支持在原子化服务中使用。
801
802**系统能力:** SystemCapability.ArkUI.ArkUI.Full
803
804**参数:**
805
806| 参数名 | 类型                                                   | 必填 | 说明                                                         |
807| ------ | ------------------------------------------------------ | ---- | ------------------------------------------------------------ |
808| index  | number                                                 | 是   | 当前显示元素的索引,索引从0开始。                                    |
809| extraInfo  | [TabsAnimationEvent](#tabsanimationevent11对象说明) | 是   | 动画相关信息,只返回主轴方向上当前显示元素相对于Tabs起始位置的位移。 |
810
811## OnTabsGestureSwipeCallback<sup>18+</sup>
812
813type OnTabsGestureSwipeCallback = (index: number, extraInfo: TabsAnimationEvent) => void
814
815在页面跟手滑动过程中,逐帧触发的回调。
816
817**原子化服务API:** 从API version 18开始,该接口支持在原子化服务中使用。
818
819**系统能力:** SystemCapability.ArkUI.ArkUI.Full
820
821**参数:**
822
823| 参数名 | 类型                                                   | 必填 | 说明                                                         |
824| ------ | ------------------------------------------------------ | ---- | ------------------------------------------------------------ |
825| index  | number                                                 | 是   | 当前显示元素的索引,索引从0开始。 <br/>取值范围:[0, 索引值-1]                                   |
826| extraInfo  | [TabsAnimationEvent](#tabsanimationevent11对象说明) | 是   | 动画相关信息,只返回主轴方向上当前显示元素相对于Tabs起始位置的位移。 |
827
828## TabsCustomContentTransitionCallback<sup>18+</sup>
829
830type TabsCustomContentTransitionCallback = (from: number, to: number) => TabContentAnimatedTransition | undefined
831
832自定义Tabs页面切换动画开始时触发的回调。
833
834**原子化服务API:** 从API version 18开始,该接口支持在原子化服务中使用。
835
836**系统能力:** SystemCapability.ArkUI.ArkUI.Full
837
838**参数:**
839
840| 参数名 | 类型   | 必填 | 说明                            |
841| ------ | ------ | ---- | ------------------------------- |
842| from   | number | 是   | 动画开始时,当前页面的index值,索引从0开始。<br/>取值范围:[0, 索引值-1],当设置的值超过索引值或小于0时无转场动画。 |
843| to     | number | 是   | 动画开始时,目标页面的index值,索引从0开始。<br/>取值范围:[0, 索引值-1],当设置的值超过索引值或小于0时无转场动画。 |
844
845**返回值:**
846
847| 类型                                                         | 说明                     |
848| ------------------------------------------------------------ | ------------------------ |
849| [TabContentAnimatedTransition](#tabcontentanimatedtransition11)&nbsp;\|&nbsp;undefined | 自定义切换动画相关信息。 |
850
851## OnTabsContentWillChangeCallback<sup>18+</sup>
852
853type OnTabsContentWillChangeCallback = (currentIndex: number, comingIndex: number) => boolean
854
855自定义Tabs页面切换拦截事件能力,新页面即将显示时触发的回调。
856
857**原子化服务API:** 从API version 18开始,该接口支持在原子化服务中使用。
858
859**系统能力:** SystemCapability.ArkUI.ArkUI.Full
860
861**参数:**
862
863| 参数名       | 类型   | 必填 | 说明                                       |
864| ------------ | ------ | ---- | ------------------------------------------ |
865| currentIndex | number | 是   | 当前显示页面的index索引,索引从0开始计算。 |
866| comingIndex  | number | 是   | 将要显示的新页面的index索引。              |
867
868**返回值:**
869
870| 类型    | 说明                                                         |
871| ------- | ------------------------------------------------------------ |
872| boolean | 当回调函数handler的返回值为true时,Tabs可以切换到新页面。<br/>当回调函数handler的返回值为false时,Tabs无法切换到新页面,仍然显示原来页面内容。 |
873
874## TabsAnimationEvent<sup>11+</sup>对象说明
875
876Tabs组件动画相关信息集合。
877
878**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
879
880**系统能力:** SystemCapability.ArkUI.ArkUI.Full
881
882| 名称            | 类型      | 只读 | 可选 | 说明                                       |
883| ------------- | ---------- | ---- | ---- | ------------------------ |
884| currentOffset | number | 否 | 否 | Tabs当前显示元素在主轴方向上,相对于Tabs起始位置的位移。单位vp,默认值为0。|
885| targetOffset | number | 否 | 否 | Tabs动画目标元素在主轴方向上,相对于Tabs起始位置的位移。单位vp,默认值为0。|
886| velocity | number | 否 | 否 | Tabs离手动画开始时的离手速度。单位vp/s,默认值为0。|
887
888## TabContentAnimatedTransition<sup>11+</sup>
889
890Tabs自定义切换动画相关信息。
891
892**卡片能力:** 从API version 11开始,该接口支持在ArkTS卡片中使用。
893
894**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
895
896**系统能力:** SystemCapability.ArkUI.ArkUI.Full
897
898| 名称            | 类型         | 必填   | 说明                                       |
899| ------------- | ---------------------- | ---- |---------------------- |
900| timeout | number | 否 | Tabs自定义切换动画超时时间。从自定义动画开始切换计时,如果到达该时间后,开发者仍未调用[TabContentTransitionProxy](#tabcontenttransitionproxy11)的finishTransition接口通知Tabs组件自定义动画结束,那么组件就会认为此次自定义动画已结束,直接执行后续操作。<br/>默认值:1000<br/>单位:ms<br/>取值范围:[0, +∞)。|
901| transition | [Callback](./ts-types.md#callback12)\<[TabContentTransitionProxy](#tabcontenttransitionproxy11)> | 是 | 自定义切换动画具体内容。|
902
903## TabContentTransitionProxy<sup>11+</sup>
904
905Tabs自定义切换动画执行过程中,返回给开发者的proxy对象。开发者可通过该对象获取自定义动画的起始和目标页面信息,同时,也可以通过调用该对象的finishTransition接口通知Tabs组件自定义动画已结束。
906
907**卡片能力:** 从API version 11开始,该接口支持在ArkTS卡片中使用。
908
909**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
910
911**系统能力:** SystemCapability.ArkUI.ArkUI.Full
912
913### 属性
914
915| 名称  | 类型     | 只读 | 可选 | 说明                         |
916| ----- | ------- | ---- | ---- | --------------------------- |
917| from | number | 否 | 否 | 自定义动画起始页面对应的index值,索引从0开始。|
918| to | number | 否 | 否 | 自定义动画目标页面对应的index值,索引从0开始。|
919
920### finishTransition
921
922finishTransition(): void
923
924通知Tabs组件,此页面的自定义动画已结束。
925
926**卡片能力:** 从API version 11开始,该接口支持在ArkTS卡片中使用。
927
928**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
929
930**系统能力:** SystemCapability.ArkUI.ArkUI.Full
931
932## TabsController
933
934Tabs组件的控制器,用于控制Tabs组件进行页签切换。不支持一个TabsController控制多个Tabs组件。
935
936**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
937
938**系统能力:** SystemCapability.ArkUI.ArkUI.Full
939
940### constructor
941
942constructor()
943
944TabsController的构造函数。
945
946**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
947
948**系统能力:** SystemCapability.ArkUI.ArkUI.Full
949
950### changeIndex
951
952changeIndex(value: number): void
953
954控制Tabs切换到指定页签。
955
956**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
957
958**系统能力:** SystemCapability.ArkUI.ArkUI.Full
959
960**参数:**
961
962| 参数名   | 类型   | 必填   | 说明                                     |
963| ----- | ------ | ---- | ---------------------------------------- |
964| value | number | 是    | 页签在Tabs里的索引值,索引值从0开始。<br/>**说明:** <br/>设置小于0或大于最大数量的值时,取默认值0。 |
965
966### preloadItems<sup>12+</sup>
967
968preloadItems(indices: Optional\<Array\<number>>): Promise\<void>
969
970控制Tabs预加载指定子节点。调用该接口后会一次性加载所有指定的子节点,因此为了性能考虑,建议分批加载子节点。
971
972**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
973
974**系统能力:** SystemCapability.ArkUI.ArkUI.Full
975
976**参数:**
977
978| 参数名   | 类型   | 必填   | 说明                                     |
979| ----- | ------ | ---- | ---------------------------------------- |
980| indices | Optional\<Array\<number>> | 是 | 需预加载的子节点的下标数组。<br/>默认值:空数组。 |
981
982**返回值:**
983
984| 类型                                                         | 说明                     |
985| ------------------------------------------------------------ | ------------------------ |
986| Promise\<void> | 预加载完成后触发的回调。 |
987
988**错误码:**
989
990以下错误码的详细介绍请参见[通用错误码](../../errorcode-universal.md)。
991
992| 错误码ID   | 错误信息                                      |
993| --------   | -------------------------------------------- |
994| 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. |
995
996### setTabBarTranslate<sup>13+</sup>
997
998setTabBarTranslate(translate: TranslateOptions): void
999
1000设置TabBar的平移距离。
1001
1002> **说明:**
1003>
1004> 当使用[bindTabsToScrollable](../arkts-apis-uicontext-uicontext.md#bindtabstoscrollable13)或[bindTabsToNestedScrollable](../arkts-apis-uicontext-uicontext.md#bindtabstonestedscrollable13)等接口绑定了Tabs组件和可滚动容器组件后,在滑动可滚动容器组件时,会触发所有与其绑定的Tabs组件的TabBar的显示和隐藏动效,调用setTabBarTranslate接口设置的TabBar平移距离会失效。因此不建议同时使用bindTabsToScrollable、bindTabsToNestedScrollable和setTabBarTranslate接口。
1005>
1006
1007**原子化服务API:** 从API version 13开始,该接口支持在原子化服务中使用。
1008
1009**系统能力:** SystemCapability.ArkUI.ArkUI.Full
1010
1011**参数:**
1012
1013| 参数名   | 类型   | 必填   | 说明                                     |
1014| ----- | ------ | ---- | ---------------------------------------- |
1015| translate | [TranslateOptions](ts-universal-attributes-transformation.md#translateoptions对象说明) | 是 | 设置TabBar的平移距离。 |
1016
1017### setTabBarOpacity<sup>13+</sup>
1018
1019setTabBarOpacity(opacity: number): void
1020
1021设置TabBar的不透明度。
1022
1023> **说明:**
1024>
1025> 当使用[bindTabsToScrollable](../arkts-apis-uicontext-uicontext.md#bindtabstoscrollable13)或[bindTabsToNestedScrollable](../arkts-apis-uicontext-uicontext.md#bindtabstonestedscrollable13)等接口绑定了Tabs组件和可滚动容器组件后,在滑动可滚动容器组件时,会触发所有与其绑定的Tabs组件的TabBar的显示和隐藏动效,调用setTabBarOpacity接口设置的TabBar不透明度会失效。因此不建议同时使用bindTabsToScrollable、bindTabsToNestedScrollable和setTabBarOpacity接口。
1026>
1027
1028**原子化服务API:** 从API version 13开始,该接口支持在原子化服务中使用。
1029
1030**系统能力:** SystemCapability.ArkUI.ArkUI.Full
1031
1032**参数:**
1033
1034| 参数名   | 类型   | 必填   | 说明                                     |
1035| ----- | ------ | ---- | ---------------------------------------- |
1036| opacity | number | 是 | 设置TabBar的不透明度,取值范围为[0.0, 1.0],设置的值小于0.0时,按0.0处理,设置的值大于1.0时,按1.0处理。<br> 默认值:1.0。 |
1037
1038## 示例
1039
1040### 示例1(设置TabBar的布局模式)
1041
1042本示例通过barMode分别实现了页签均分布局和以实际长度布局,且展示了当页签布局长度之和超过了TabBar总长度后可滑动的效果。
1043
1044```ts
1045// xxx.ets
1046@Entry
1047@Component
1048struct TabsExample {
1049  @State text: string = '文本';
1050  @State barMode: BarMode = BarMode.Fixed;
1051
1052  build() {
1053    Column() {
1054      Row() {
1055        Button('文本增加 ')
1056          .width('47%')
1057          .height(50)
1058          .onClick((event?: ClickEvent) => {
1059            this.text += '文本增加';
1060          })
1061          .margin({ right: '6%', bottom: '12vp' })
1062
1063        Button('文本重置')
1064          .width('47%')
1065          .height(50)
1066          .onClick((event?: ClickEvent) => {
1067            this.text = '文本';
1068          })
1069          .margin({ bottom: '12vp' })
1070      }
1071
1072      Row() {
1073        Button('BarMode.Fixed')
1074          .width('47%')
1075          .height(50)
1076          .onClick((event?: ClickEvent) => {
1077            this.barMode = BarMode.Fixed;
1078          })
1079          .margin({ right: '6%', bottom: '12vp' })
1080
1081        Button('BarMode.Scrollable')
1082          .width('47%')
1083          .height(50)
1084          .onClick((event?: ClickEvent) => {
1085            this.barMode = BarMode.Scrollable;
1086          })
1087          .margin({ bottom: '12vp' })
1088      }
1089
1090      Tabs() {
1091        TabContent() {
1092          Column().width('100%').height('100%').backgroundColor(Color.Pink)
1093        }.tabBar(SubTabBarStyle.of(this.text))
1094
1095        TabContent() {
1096          Column().width('100%').height('100%').backgroundColor(Color.Green)
1097        }.tabBar(SubTabBarStyle.of(this.text))
1098
1099        TabContent() {
1100          Column().width('100%').height('100%').backgroundColor(Color.Blue)
1101        }.tabBar(SubTabBarStyle.of(this.text))
1102      }
1103      .height('60%')
1104      .backgroundColor(0xf1f3f5)
1105      .barMode(this.barMode)
1106    }
1107    .width('100%')
1108    .height(500)
1109    .padding('24vp')
1110  }
1111}
1112```
1113![tabs1](figures/tabs_barMode.gif)
1114
1115### 示例2(设置Scrollable模式下的TabBar的布局样式)
1116
1117本示例实现了barMode的ScrollableBarModeOptions参数,该参数仅在Scrollable模式下有效。
1118
1119```ts
1120// xxx.ets
1121@Entry
1122@Component
1123struct TabsExample6 {
1124  private controller: TabsController = new TabsController();
1125  @State scrollMargin: number = 0;
1126  @State layoutStyle: LayoutStyle = LayoutStyle.ALWAYS_CENTER;
1127  @State text: string = '文本';
1128
1129  build() {
1130    Column() {
1131      Row() {
1132        Button('scrollMargin+10 ' + this.scrollMargin)
1133          .width('47%')
1134          .height(50)
1135          .margin({ top: 5 })
1136          .onClick((event?: ClickEvent) => {
1137            this.scrollMargin += 10;
1138          })
1139          .margin({ right: '6%', bottom: '12vp' })
1140        Button('scrollMargin-10 ' + this.scrollMargin)
1141          .width('47%')
1142          .height(50)
1143          .margin({ top: 5 })
1144          .onClick((event?: ClickEvent) => {
1145            this.scrollMargin -= 10;
1146          })
1147          .margin({ bottom: '12vp' })
1148      }
1149
1150      Row() {
1151        Button('文本增加 ')
1152          .width('47%')
1153          .height(50)
1154          .margin({ top: 5 })
1155          .onClick((event?: ClickEvent) => {
1156            this.text += '文本增加';
1157          })
1158          .margin({ right: '6%', bottom: '12vp' })
1159        Button('文本重置')
1160          .width('47%')
1161          .height(50)
1162          .margin({ top: 5 })
1163          .onClick((event?: ClickEvent) => {
1164            this.text = '文本';
1165          })
1166          .margin({ bottom: '12vp' })
1167      }
1168
1169      Row() {
1170        Button('layoutStyle.ALWAYS_CENTER')
1171          .width('100%')
1172          .height(50)
1173          .margin({ top: 5 })
1174          .fontSize(15)
1175          .onClick((event?: ClickEvent) => {
1176            this.layoutStyle = LayoutStyle.ALWAYS_CENTER;
1177          })
1178          .margin({ bottom: '12vp' })
1179      }
1180
1181      Row() {
1182        Button('layoutStyle.ALWAYS_AVERAGE_SPLIT')
1183          .width('100%')
1184          .height(50)
1185          .margin({ top: 5 })
1186          .fontSize(15)
1187          .onClick((event?: ClickEvent) => {
1188            this.layoutStyle = LayoutStyle.ALWAYS_AVERAGE_SPLIT;
1189          })
1190          .margin({ bottom: '12vp' })
1191      }
1192
1193      Row() {
1194        Button('layoutStyle.SPACE_BETWEEN_OR_CENTER')
1195          .width('100%')
1196          .height(50)
1197          .margin({ top: 5 })
1198          .fontSize(15)
1199          .onClick((event?: ClickEvent) => {
1200            this.layoutStyle = LayoutStyle.SPACE_BETWEEN_OR_CENTER;
1201          })
1202          .margin({ bottom: '12vp' })
1203      }
1204
1205      Tabs({ barPosition: BarPosition.End, controller: this.controller }) {
1206        TabContent() {
1207          Column().width('100%').height('100%').backgroundColor(Color.Pink)
1208        }.tabBar(SubTabBarStyle.of(this.text))
1209
1210        TabContent() {
1211          Column().width('100%').height('100%').backgroundColor(Color.Green)
1212        }.tabBar(SubTabBarStyle.of(this.text))
1213
1214        TabContent() {
1215          Column().width('100%').height('100%').backgroundColor(Color.Blue)
1216        }.tabBar(SubTabBarStyle.of(this.text))
1217      }
1218      .animationDuration(300)
1219      .height('60%')
1220      .backgroundColor(0xf1f3f5)
1221      .barMode(BarMode.Scrollable, { margin: this.scrollMargin, nonScrollableLayoutStyle: this.layoutStyle })
1222    }
1223    .width('100%')
1224    .height(500)
1225    .margin({ top: 5 })
1226    .padding('24vp')
1227  }
1228}
1229```
1230
1231![tabs2](figures/tabs_scrollable.gif)
1232
1233### 示例3(自定义页签切换联动)
1234
1235本示例通过onAnimationStart、onChange实现切换时自定义tabBar和TabContent的联动。
1236
1237```ts
1238// xxx.ets
1239@Entry
1240@Component
1241struct TabsExample {
1242  @State fontColor: string = '#182431';
1243  @State selectedFontColor: string = '#007DFF';
1244  @State currentIndex: number = 0;
1245  @State selectedIndex: number = 0;
1246  private controller: TabsController = new TabsController();
1247
1248  @Builder tabBuilder(index: number, name: string) {
1249    Column() {
1250      Text(name)
1251        .fontColor(this.selectedIndex === index ? this.selectedFontColor : this.fontColor)
1252        .fontSize(16)
1253        .fontWeight(this.selectedIndex === index ? 500 : 400)
1254        .lineHeight(22)
1255        .margin({ top: 17, bottom: 7 })
1256      Divider()
1257        .strokeWidth(2)
1258        .color('#007DFF')
1259        .opacity(this.selectedIndex === index ? 1 : 0)
1260    }.width('100%')
1261  }
1262
1263  build() {
1264    Column() {
1265      Tabs({ barPosition: BarPosition.Start, index: this.currentIndex, controller: this.controller }) {
1266        TabContent() {
1267          Column().width('100%').height('100%').backgroundColor('#00CB87')
1268        }.tabBar(this.tabBuilder(0, 'green'))
1269
1270        TabContent() {
1271          Column().width('100%').height('100%').backgroundColor('#007DFF')
1272        }.tabBar(this.tabBuilder(1, 'blue'))
1273
1274        TabContent() {
1275          Column().width('100%').height('100%').backgroundColor('#FFBF00')
1276        }.tabBar(this.tabBuilder(2, 'yellow'))
1277
1278        TabContent() {
1279          Column().width('100%').height('100%').backgroundColor('#E67C92')
1280        }.tabBar(this.tabBuilder(3, 'pink'))
1281      }
1282      .vertical(false)
1283      .barMode(BarMode.Fixed)
1284      .barWidth(360)
1285      .barHeight(56)
1286      .animationDuration(400)
1287      .onChange((index: number) => {
1288        // currentIndex控制TabContent显示页签
1289        this.currentIndex = index;
1290        this.selectedIndex = index;
1291      })
1292      .onAnimationStart((index: number, targetIndex: number, event: TabsAnimationEvent) => {
1293        if (index === targetIndex) {
1294          return;
1295        }
1296        // selectedIndex控制自定义TabBar内Image和Text颜色切换
1297        this.selectedIndex = targetIndex;
1298      })
1299      .width(360)
1300      .height(296)
1301      .margin({ top: 52 })
1302      .backgroundColor('#F1F3F5')
1303    }.width('100%')
1304  }
1305}
1306```
1307
1308![tabs3](figures/tabs_onAnimationStart.gif)
1309
1310### 示例4(分割线基本属性)
1311
1312本示例通过divider实现了分割线各种属性的展示。
1313
1314```ts
1315// xxx.ets
1316@Entry
1317@Component
1318struct TabsDivider1 {
1319  private controller1: TabsController = new TabsController();
1320  @State dividerColor: string = 'red';
1321  @State strokeWidth: number = 2;
1322  @State startMargin: number = 0;
1323  @State endMargin: number = 0;
1324  @State nullFlag: boolean = false;
1325
1326  build() {
1327    Column() {
1328      Tabs({ controller: this.controller1 }) {
1329        TabContent() {
1330          Column().width('100%').height('100%').backgroundColor(Color.Pink)
1331        }.tabBar('pink')
1332
1333        TabContent() {
1334          Column().width('100%').height('100%').backgroundColor(Color.Yellow)
1335        }.tabBar('yellow')
1336
1337        TabContent() {
1338          Column().width('100%').height('100%').backgroundColor(Color.Blue)
1339        }.tabBar('blue')
1340
1341        TabContent() {
1342          Column().width('100%').height('100%').backgroundColor(Color.Green)
1343        }.tabBar('green')
1344
1345        TabContent() {
1346          Column().width('100%').height('100%').backgroundColor(Color.Red)
1347        }.tabBar('red')
1348      }
1349      .vertical(true)
1350      .scrollable(true)
1351      .barMode(BarMode.Fixed)
1352      .barWidth(70)
1353      .barHeight(200)
1354      .animationDuration(400)
1355      .onChange((index: number) => {
1356        console.info(index.toString());
1357      })
1358      .height('200vp')
1359      .margin({ bottom: '12vp' })
1360      .divider(this.nullFlag ? null : {
1361        strokeWidth: this.strokeWidth,
1362        color: this.dividerColor,
1363        startMargin: this.startMargin,
1364        endMargin: this.endMargin
1365      })
1366
1367      Button('常规Divider').width('100%').margin({ bottom: '12vp' })
1368        .onClick(() => {
1369          this.nullFlag = false;
1370          this.strokeWidth = 2;
1371          this.dividerColor = 'red';
1372          this.startMargin = 0;
1373          this.endMargin = 0;
1374        })
1375      Button('空Divider').width('100%').margin({ bottom: '12vp' })
1376        .onClick(() => {
1377          this.nullFlag = true;
1378        })
1379      Button('颜色变为蓝色').width('100%').margin({ bottom: '12vp' })
1380        .onClick(() => {
1381          this.dividerColor = 'blue';
1382        })
1383      Button('宽度增加').width('100%').margin({ bottom: '12vp' })
1384        .onClick(() => {
1385          this.strokeWidth += 2;
1386        })
1387      Button('宽度减小').width('100%').margin({ bottom: '12vp' })
1388        .onClick(() => {
1389          if (this.strokeWidth > 2) {
1390            this.strokeWidth -= 2;
1391          }
1392        })
1393      Button('上边距增加').width('100%').margin({ bottom: '12vp' })
1394        .onClick(() => {
1395          this.startMargin += 2;
1396        })
1397      Button('上边距减少').width('100%').margin({ bottom: '12vp' })
1398        .onClick(() => {
1399          if (this.startMargin > 2) {
1400            this.startMargin -= 2;
1401          }
1402        })
1403      Button('下边距增加').width('100%').margin({ bottom: '12vp' })
1404        .onClick(() => {
1405          this.endMargin += 2;
1406        })
1407      Button('下边距减少').width('100%').margin({ bottom: '12vp' })
1408        .onClick(() => {
1409          if (this.endMargin > 2) {
1410            this.endMargin -= 2;
1411          }
1412        })
1413    }.padding({ top: '24vp', left: '24vp', right: '24vp' })
1414  }
1415}
1416```
1417
1418![tabs4](figures/tabs_divider.gif)
1419
1420### 示例5(设置TabBar渐隐)
1421
1422本示例通过fadingEdge实现了切换子页签渐隐和不渐隐。
1423
1424```ts
1425// xxx.ets
1426@Entry
1427@Component
1428struct TabsOpaque {
1429  @State message: string = 'Hello World';
1430  private controller: TabsController = new TabsController();
1431  private controller1: TabsController = new TabsController();
1432  @State selfFadingFade: boolean = true;
1433
1434  build() {
1435    Column() {
1436      Button('子页签设置渐隐').width('100%').margin({ bottom: '12vp' })
1437        .onClick((event?: ClickEvent) => {
1438          this.selfFadingFade = true;
1439        })
1440      Button('子页签设置不渐隐').width('100%').margin({ bottom: '12vp' })
1441        .onClick((event?: ClickEvent) => {
1442          this.selfFadingFade = false;
1443        })
1444      Tabs({ barPosition: BarPosition.End, controller: this.controller }) {
1445        TabContent() {
1446          Column().width('100%').height('100%').backgroundColor(Color.Pink)
1447        }.tabBar('pink')
1448
1449        TabContent() {
1450          Column().width('100%').height('100%').backgroundColor(Color.Yellow)
1451        }.tabBar('yellow')
1452
1453        TabContent() {
1454          Column().width('100%').height('100%').backgroundColor(Color.Blue)
1455        }.tabBar('blue')
1456
1457        TabContent() {
1458          Column().width('100%').height('100%').backgroundColor(Color.Green)
1459        }.tabBar('green')
1460
1461        TabContent() {
1462          Column().width('100%').height('100%').backgroundColor(Color.Green)
1463        }.tabBar('green')
1464
1465        TabContent() {
1466          Column().width('100%').height('100%').backgroundColor(Color.Green)
1467        }.tabBar('green')
1468
1469        TabContent() {
1470          Column().width('100%').height('100%').backgroundColor(Color.Green)
1471        }.tabBar('green')
1472
1473        TabContent() {
1474          Column().width('100%').height('100%').backgroundColor(Color.Green)
1475        }.tabBar('green')
1476      }
1477      .vertical(false)
1478      .scrollable(true)
1479      .barMode(BarMode.Scrollable)
1480      .barHeight(80)
1481      .animationDuration(400)
1482      .onChange((index: number) => {
1483        console.info(index.toString());
1484      })
1485      .fadingEdge(this.selfFadingFade)
1486      .height('30%')
1487      .width('100%')
1488
1489      Tabs({ barPosition: BarPosition.Start, controller: this.controller1 }) {
1490        TabContent() {
1491          Column().width('100%').height('100%').backgroundColor(Color.Pink)
1492        }.tabBar('pink')
1493
1494        TabContent() {
1495          Column().width('100%').height('100%').backgroundColor(Color.Yellow)
1496        }.tabBar('yellow')
1497
1498        TabContent() {
1499          Column().width('100%').height('100%').backgroundColor(Color.Blue)
1500        }.tabBar('blue')
1501
1502        TabContent() {
1503          Column().width('100%').height('100%').backgroundColor(Color.Green)
1504        }.tabBar('green')
1505
1506        TabContent() {
1507          Column().width('100%').height('100%').backgroundColor(Color.Green)
1508        }.tabBar('green')
1509
1510        TabContent() {
1511          Column().width('100%').height('100%').backgroundColor(Color.Green)
1512        }.tabBar('green')
1513      }
1514      .vertical(true)
1515      .scrollable(true)
1516      .barMode(BarMode.Scrollable)
1517      .barHeight(200)
1518      .barWidth(80)
1519      .animationDuration(400)
1520      .onChange((index: number) => {
1521        console.info(index.toString());
1522      })
1523      .fadingEdge(this.selfFadingFade)
1524      .height('30%')
1525      .width('100%')
1526    }
1527    .padding({ top: '24vp', left: '24vp', right: '24vp' })
1528  }
1529}
1530```
1531
1532![tabs5](figures/tabs_fadingEdge.gif)
1533
1534### 示例6(设置TabBar叠加在TabContent内容上)
1535
1536本示例通过barOverlap实现了TabBar是否背后变模糊并叠加在TabContent之上。
1537
1538```ts
1539// xxx.ets
1540@Entry
1541@Component
1542struct barHeightTest {
1543  @State arr: number[] = [0, 1, 2, 3];
1544  @State barOverlap: boolean = true;
1545
1546  build() {
1547    Column() {
1548      Text(`barOverlap ${this.barOverlap}`).fontSize(16)
1549      Button('barOverlap变化').width('100%').margin({ bottom: '12vp' })
1550        .onClick((event?: ClickEvent) => {
1551          if (this.barOverlap) {
1552            this.barOverlap = false;
1553          } else {
1554            this.barOverlap = true;
1555          }
1556        })
1557
1558      Tabs({ barPosition: BarPosition.End }) {
1559        TabContent() {
1560          Column() {
1561            List({ space: 10 }) {
1562              ForEach(this.arr, (item: number) => {
1563                ListItem() {
1564                  Text('item' + item).width('80%').height(200).fontSize(16).textAlign(TextAlign.Center).backgroundColor('#fff8b81e')
1565                }
1566              }, (item: string) => item)
1567            }.width('100%').height('100%')
1568            .lanes(2).alignListItem(ListItemAlign.Center)
1569          }.width('100%').height('100%')
1570          .backgroundColor(Color.Pink)
1571        }
1572        .tabBar(new BottomTabBarStyle($r('sys.media.ohos_icon_mask_svg'), '测试0'))
1573      }
1574      .scrollable(false)
1575      .height('60%')
1576      .barOverlap(this.barOverlap)
1577    }
1578    .height(500)
1579    .padding({ top: '24vp', left: '24vp', right: '24vp' })
1580  }
1581}
1582```
1583
1584![tabs6](figures/tabs_barOverlap.gif)
1585
1586### 示例7(设置TabBar栅格化可见区域)
1587
1588本示例通过barGridAlign实现了以栅格化方式设置TabBar的可见区域。
1589
1590```ts
1591// xxx.ets
1592@Entry
1593@Component
1594struct TabsExample5 {
1595  private controller: TabsController = new TabsController();
1596  @State gridMargin: number = 10;
1597  @State gridGutter: number = 10;
1598  @State sm: number = -2;
1599  @State clickedContent: string = '';
1600
1601  build() {
1602    Column() {
1603      Row() {
1604        Button('gridMargin+10 ' + this.gridMargin)
1605          .width('47%')
1606          .height(50)
1607          .margin({ top: 5 })
1608          .onClick((event?: ClickEvent) => {
1609            this.gridMargin += 10;
1610          })
1611          .margin({ right: '6%', bottom: '12vp' })
1612        Button('gridMargin-10 ' + this.gridMargin)
1613          .width('47%')
1614          .height(50)
1615          .margin({ top: 5 })
1616          .onClick((event?: ClickEvent) => {
1617            this.gridMargin -= 10;
1618          })
1619          .margin({ bottom: '12vp' })
1620      }
1621
1622      Row() {
1623        Button('gridGutter+10 ' + this.gridGutter)
1624          .width('47%')
1625          .height(50)
1626          .margin({ top: 5 })
1627          .onClick((event?: ClickEvent) => {
1628            this.gridGutter += 10;
1629          })
1630          .margin({ right: '6%', bottom: '12vp' })
1631        Button('gridGutter-10 ' + this.gridGutter)
1632          .width('47%')
1633          .height(50)
1634          .margin({ top: 5 })
1635          .onClick((event?: ClickEvent) => {
1636            this.gridGutter -= 10;
1637          })
1638          .margin({ bottom: '12vp' })
1639      }
1640
1641      Row() {
1642        Button('sm+2 ' + this.sm)
1643          .width('47%')
1644          .height(50)
1645          .margin({ top: 5 })
1646          .onClick((event?: ClickEvent) => {
1647            this.sm += 2;
1648          })
1649          .margin({ right: '6%' })
1650        Button('sm-2 ' + this.sm).width('47%').height(50).margin({ top: 5 })
1651          .onClick((event?: ClickEvent) => {
1652            this.sm -= 2;
1653          })
1654      }
1655
1656      Text('点击内容:' + this.clickedContent).width('100%').height(200).margin({ top: 5 })
1657
1658
1659      Tabs({ barPosition: BarPosition.End, controller: this.controller }) {
1660        TabContent() {
1661          Column().width('100%').height('100%').backgroundColor(Color.Pink)
1662        }.tabBar(BottomTabBarStyle.of($r('sys.media.ohos_app_icon'), '1'))
1663
1664        TabContent() {
1665          Column().width('100%').height('100%').backgroundColor(Color.Green)
1666        }.tabBar(BottomTabBarStyle.of($r('sys.media.ohos_app_icon'), '2'))
1667
1668        TabContent() {
1669          Column().width('100%').height('100%').backgroundColor(Color.Blue)
1670        }.tabBar(BottomTabBarStyle.of($r('sys.media.ohos_app_icon'), '3'))
1671      }
1672      .width('350vp')
1673      .animationDuration(300)
1674      .height('60%')
1675      .barGridAlign({ sm: this.sm, margin: this.gridMargin, gutter: this.gridGutter })
1676      .backgroundColor(0xf1f3f5)
1677      .onTabBarClick((index: number) => {
1678        this.clickedContent += 'now index ' + index + ' is clicked\n';
1679      })
1680    }
1681    .width('100%')
1682    .height(500)
1683    .margin({ top: 5 })
1684    .padding('10vp')
1685  }
1686}
1687```
1688
1689![tabs7](figures/tabs_barGridAlign.gif)
1690
1691### 示例8(自定义Tabs页面切换动画)
1692
1693本示例通过customContentTransition实现了自定义Tabs页面的切换动画。
1694
1695```ts
1696// xxx.ets
1697interface itemType {
1698  text: string,
1699  backgroundColor: Color
1700}
1701
1702@Entry
1703@Component
1704struct TabsCustomAnimationExample {
1705  @State data: itemType[] = [
1706    {
1707      text: 'Red',
1708      backgroundColor: Color.Red
1709    },
1710    {
1711      text: 'Yellow',
1712      backgroundColor: Color.Yellow
1713    },
1714    {
1715      text: 'Blue',
1716      backgroundColor: Color.Blue
1717    }];
1718  @State opacityList: number[] = [];
1719  @State scaleList: number[] = [];
1720
1721  private durationList: number[] = [];
1722  private timeoutList: number[] = [];
1723  private customContentTransition: (from: number, to: number) => TabContentAnimatedTransition = (from: number, to: number) => {
1724    let tabContentAnimatedTransition = {
1725      timeout: this.timeoutList[from],
1726      transition: (proxy: TabContentTransitionProxy) => {
1727        this.scaleList[from] = 1.0;
1728        this.scaleList[to] = 0.5;
1729        this.opacityList[from] = 1.0;
1730        this.opacityList[to] = 0.5;
1731        this.getUIContext()?.animateTo({
1732          duration: this.durationList[from],
1733          onFinish: () => {
1734            proxy.finishTransition();
1735          }
1736        }, () => {
1737          this.scaleList[from] = 0.5;
1738          this.scaleList[to] = 1.0;
1739          this.opacityList[from] = 0.5;
1740          this.opacityList[to] = 1.0;
1741        });
1742      }
1743    } as TabContentAnimatedTransition;
1744    return tabContentAnimatedTransition;
1745  };
1746
1747  aboutToAppear(): void {
1748    let duration = 1000;
1749    let timeout = 1000;
1750    for (let i = 1; i <= this.data.length; i++) {
1751      this.opacityList.push(1.0);
1752      this.scaleList.push(1.0);
1753      this.durationList.push(duration * i);
1754      this.timeoutList.push(timeout * i);
1755    }
1756  }
1757
1758  build() {
1759    Column() {
1760      Tabs() {
1761        ForEach(this.data, (item: itemType, index: number) => {
1762          TabContent() {}
1763          .tabBar(item.text)
1764          .backgroundColor(item.backgroundColor)
1765          // 自定义动画变化透明度、缩放页面等
1766          .opacity(this.opacityList[index])
1767          .scale({ x: this.scaleList[index], y: this.scaleList[index] })
1768        })
1769      }
1770      .backgroundColor(0xf1f3f5)
1771      .width('100%')
1772      .height(500)
1773      .customContentTransition(this.customContentTransition)
1774    }
1775  }
1776}
1777```
1778
1779![tabs8](figures/tabs8.gif)
1780
1781### 示例9(页面切换拦截)
1782
1783本示例通过onContentWillChange实现了自定义页面手势滑动切换拦截。
1784
1785```ts
1786//xxx.ets
1787@Entry
1788@Component
1789struct TabsExample {
1790  @State selectedIndex: number = 2;
1791  @State currentIndex: number = 2;
1792  private controller: TabsController = new TabsController();
1793
1794  @Builder tabBuilder(title: string,targetIndex: number) {
1795    Column(){
1796      // $r('app.media.star_fill')需要替换为开发者所需的图像资源文件
1797      // $r('app.media.star')需要替换为开发者所需的图像资源文件
1798      Image(this.selectedIndex === targetIndex ? $r('app.media.star_fill') : $r('app.media.star'))
1799        .width(24)
1800        .height(24)
1801        .margin({ bottom: 4 })
1802        .objectFit(ImageFit.Contain)
1803      Text(title).fontColor(this.selectedIndex === targetIndex ? '#1698CE' : '#6B6B6B')
1804    }.width('100%')
1805    .height(50)
1806    .justifyContent(FlexAlign.Center)
1807  }
1808
1809  build() {
1810    Column() {
1811      Tabs({ barPosition: BarPosition.End, index: this.currentIndex, controller: this.controller }) {
1812        TabContent() {
1813          Column(){
1814            Text('首页的内容')
1815          }.width('100%').height('100%').backgroundColor('#00CB87').justifyContent(FlexAlign.Center)
1816        }.tabBar(this.tabBuilder('首页',0))
1817
1818        TabContent() {
1819          Column(){
1820            Text('发现的内容')
1821          }.width('100%').height('100%').backgroundColor('#007DFF').justifyContent(FlexAlign.Center)
1822        }.tabBar(this.tabBuilder('发现',1))
1823
1824        TabContent() {
1825          Column(){
1826            Text('推荐的内容')
1827          }.width('100%').height('100%').backgroundColor('#FFBF00').justifyContent(FlexAlign.Center)
1828        }.tabBar(this.tabBuilder('推荐',2))
1829
1830        TabContent() {
1831          Column(){
1832            Text('我的内容')
1833          }.width('100%').height('100%').backgroundColor('#E67C92').justifyContent(FlexAlign.Center)
1834        }.tabBar(this.tabBuilder('我的',3))
1835      }
1836      .vertical(false)
1837      .barMode(BarMode.Fixed)
1838      .barWidth(360)
1839      .barHeight(60)
1840      .animationDuration(0)
1841      .onChange((index: number) => {
1842        this.currentIndex = index;
1843        this.selectedIndex = index;
1844      })
1845      .width(360)
1846      .height(600)
1847      .backgroundColor('#F1F3F5')
1848      .scrollable(true)
1849      .onContentWillChange((currentIndex, comingIndex) => {
1850        if (comingIndex == 2) {
1851          return false;
1852        }
1853        return true;
1854      })
1855
1856      Button('动态修改index').width('50%').margin({ top: 20 })
1857        .onClick(()=>{
1858          this.currentIndex = (this.currentIndex + 1) % 4;
1859        })
1860
1861      Button('changeIndex').width('50%').margin({ top: 20 })
1862        .onClick(()=>{
1863          this.currentIndex = (this.currentIndex + 1) % 4;
1864          this.controller.changeIndex(this.currentIndex);
1865        })
1866    }.width('100%')
1867  }
1868}
1869```
1870
1871![tabs9](figures/tabs9.gif)
1872
1873### 示例10(自定义TabBar切换动画)
1874
1875本示例通过onChange、onAnimationStart、onAnimationEnd、onGestureSwipe等接口实现了自定义TabBar的切换动画。
1876
1877<!--code_no_check-->
1878
1879```ts
1880// EntryAbility.ets
1881import { Configuration, UIAbility } from '@kit.AbilityKit';
1882import { i18n } from '@kit.LocalizationKit';
1883import { CommonUtil } from '../common/CommonUtil';
1884
1885export default class EntryAbility extends UIAbility {
1886  onConfigurationUpdate(newConfig: Configuration): void {
1887    // 监听系统配置变化
1888    if (newConfig.language) {
1889      CommonUtil.setIsRTL(i18n.isRTL(newConfig.language));
1890    }
1891  }
1892}
1893```
1894
1895<!--code_no_check-->
1896
1897```ts
1898// CommonUtil.ets
1899export class CommonUtil {
1900  private static isRTL: boolean = false;
1901
1902  public static setIsRTL(isRTL: boolean): void {
1903    CommonUtil.isRTL = isRTL;
1904  }
1905
1906  public static getIsRTL(): boolean {
1907    return CommonUtil.isRTL;
1908  }
1909}
1910```
1911
1912<!--code_no_check-->
1913
1914```ts
1915// xxx.ets
1916import { LengthMetrics } from '@kit.ArkUI';
1917import { CommonUtil } from '../common/CommonUtil';
1918
1919@Entry
1920@Component
1921struct TabsExample {
1922  @State colorArray: [string, string][] =
1923    [['green', '#00CB87'], ['blue', '#007DFF'], ['yellow', '#FFBF00'], ['pink', '#E67C92']];
1924  @State currentIndex: number = 0;
1925  @State animationDuration: number = 300;
1926  @State indicatorLeftMargin: number = 0;
1927  @State indicatorWidth: number = 0;
1928  private tabsWidth: number = 0;
1929  private textInfos: [number, number][] = [];
1930  private isStartAnimateTo: boolean = false;
1931
1932  aboutToAppear():void {
1933    for (let i = 0; i < this.colorArray.length; i++) {
1934      this.textInfos.push([0, 0]);
1935    }
1936  }
1937
1938  @Builder
1939  tabBuilder(index: number, name: string) {
1940    Column() {
1941      Text(name)
1942        .fontSize(16)
1943        .fontColor(this.currentIndex === index ? '#007DFF' : '#182431')
1944        .fontWeight(this.currentIndex === index ? 500 : 400)
1945        .id(index.toString())
1946        .onAreaChange((oldValue: Area, newValue: Area) => {
1947          this.textInfos[index] = [newValue.globalPosition.x as number, newValue.width as number];
1948          if (!this.isStartAnimateTo && this.currentIndex === index && this.tabsWidth > 0) {
1949            this.setIndicatorAttr(this.textInfos[this.currentIndex][0], this.textInfos[this.currentIndex][1]);
1950          }
1951        })
1952    }.width('100%')
1953  }
1954
1955  build() {
1956    Stack({ alignContent: Alignment.TopStart }) {
1957      Tabs({ barPosition: BarPosition.Start }) {
1958        ForEach(this.colorArray, (item: [string, string], index:number) => {
1959          TabContent() {
1960            Column().width('100%').height('100%').backgroundColor(item[1])
1961          }.tabBar(this.tabBuilder(index, item[0]))
1962        })
1963      }
1964      .onAreaChange((oldValue: Area, newValue: Area)=> {
1965        this.tabsWidth = newValue.width as number;
1966        if (!this.isStartAnimateTo) {
1967          this.setIndicatorAttr(this.textInfos[this.currentIndex][0], this.textInfos[this.currentIndex][1]);
1968        }
1969      })
1970      .barWidth('100%')
1971      .barHeight(56)
1972      .width('100%')
1973      .height(296)
1974      .backgroundColor('#F1F3F5')
1975      .animationDuration(this.animationDuration)
1976      .onChange((index: number) => {
1977        this.currentIndex = index; // 监听索引index的变化,实现页签内容的切换。
1978      })
1979      .onAnimationStart((index: number, targetIndex: number, event: TabsAnimationEvent) => {
1980        // 切换动画开始时触发该回调。下划线跟着页面一起滑动,同时宽度渐变。
1981        this.currentIndex = targetIndex;
1982        this.startAnimateTo(this.animationDuration, this.textInfos[targetIndex][0], this.textInfos[targetIndex][1]);
1983      })
1984      .onAnimationEnd((index: number, event: TabsAnimationEvent) => {
1985        // 切换动画结束时触发该回调。下划线动画停止。
1986        let currentIndicatorInfo = this.getCurrentIndicatorInfo(index, event);
1987        this.startAnimateTo(0, currentIndicatorInfo.left, currentIndicatorInfo.width);
1988      })
1989      .onGestureSwipe((index: number, event: TabsAnimationEvent) => {
1990        // 在页面跟手滑动过程中,逐帧触发该回调。
1991        let currentIndicatorInfo = this.getCurrentIndicatorInfo(index, event);
1992        this.currentIndex = currentIndicatorInfo.index;
1993        this.setIndicatorAttr(currentIndicatorInfo.left, currentIndicatorInfo.width);
1994      })
1995
1996      Column()
1997        .height(2)
1998        .width(this.indicatorWidth)
1999        .margin({ start: LengthMetrics.vp(this.indicatorLeftMargin), top: LengthMetrics.vp(48) })
2000        .backgroundColor('#007DFF')
2001    }.width('100%')
2002  }
2003
2004  private getCurrentIndicatorInfo(index: number, event: TabsAnimationEvent): Record<string, number> {
2005    let nextIndex = index;
2006    if (index > 0 && (CommonUtil.getIsRTL() ? event.currentOffset < 0 : event.currentOffset > 0)) {
2007      nextIndex--;
2008    } else if (index < this.textInfos.length - 1 &&
2009        (CommonUtil.getIsRTL() ? event.currentOffset > 0 : event.currentOffset < 0)) {
2010      nextIndex++;
2011    }
2012    let indexInfo = this.textInfos[index];
2013    let nextIndexInfo = this.textInfos[nextIndex];
2014    let swipeRatio = Math.abs(event.currentOffset / this.tabsWidth);
2015    let currentIndex = swipeRatio > 0.5 ? nextIndex : index; // 页面滑动超过一半,tabBar切换到下一页。
2016    let currentLeft = indexInfo[0] + (nextIndexInfo[0] - indexInfo[0]) * swipeRatio;
2017    let currentWidth = indexInfo[1] + (nextIndexInfo[1] - indexInfo[1]) * swipeRatio;
2018    return { 'index': currentIndex, 'left': currentLeft, 'width': currentWidth };
2019  }
2020
2021  private startAnimateTo(duration: number, leftMargin: number, width: number) {
2022    this.isStartAnimateTo = true;
2023    this.getUIContext()?.animateTo({
2024      duration: duration, // 动画时长
2025      curve: Curve.Linear, // 动画曲线
2026      iterations: 1, // 播放次数
2027      playMode: PlayMode.Normal, // 动画模式
2028      onFinish: () => {
2029        this.isStartAnimateTo = false;
2030        console.info('play end');
2031      }
2032    }, () => {
2033      this.setIndicatorAttr(leftMargin, width);
2034    });
2035  }
2036
2037  private setIndicatorAttr(leftMargin: number, width: number) {
2038    this.indicatorWidth = width;
2039    if (CommonUtil.getIsRTL()) {
2040      this.indicatorLeftMargin = this.tabsWidth - leftMargin - width;
2041    } else {
2042      this.indicatorLeftMargin = leftMargin;
2043    }
2044  }
2045}
2046```
2047
2048![tabs10](figures/tabs10.gif)
2049
2050### 示例11(预加载子节点)
2051
2052本示例通过preloadItems接口实现了预加载指定子节点。
2053
2054```ts
2055// xxx.ets
2056import { BusinessError } from '@kit.BasicServicesKit';
2057
2058@Entry
2059@Component
2060struct TabsPreloadItems {
2061  @State currentIndex: number = 1;
2062  private tabsController: TabsController = new TabsController();
2063
2064  build() {
2065    Column() {
2066      Tabs({ index: this.currentIndex, controller: this.tabsController }) {
2067        TabContent() {
2068          MyComponent({ color: '#00CB87' })
2069        }.tabBar(SubTabBarStyle.of('green'))
2070
2071        TabContent() {
2072          MyComponent({ color: '#007DFF' })
2073        }.tabBar(SubTabBarStyle.of('blue'))
2074
2075        TabContent() {
2076          MyComponent({ color: '#FFBF00' })
2077        }.tabBar(SubTabBarStyle.of('yellow'))
2078
2079        TabContent() {
2080          MyComponent({ color: '#E67C92' })
2081        }.tabBar(SubTabBarStyle.of('pink'))
2082      }
2083      .width(360)
2084      .height(296)
2085      .backgroundColor('#F1F3F5')
2086      .onChange((index: number) => {
2087        this.currentIndex = index;
2088      })
2089
2090      Button('preload items: [0, 2, 3]')
2091        .margin(5)
2092        .onClick(() => {
2093          // 预加载第0、2、3个子节点,提高滑动或点击切换至这些节点时的性能
2094          this.tabsController.preloadItems([0, 2, 3])
2095            .then(() => {
2096              console.info('preloadItems success.');
2097            })
2098            .catch((error: BusinessError) => {
2099              console.error('preloadItems failed, error code: ' + error.code + ', error message: ' + error.message);
2100            })
2101        })
2102    }
2103  }
2104}
2105
2106@Component
2107struct MyComponent {
2108  private color: string = '';
2109
2110  aboutToAppear(): void {
2111    console.info('aboutToAppear backgroundColor:' + this.color);
2112  }
2113
2114  aboutToDisappear(): void {
2115    console.info('aboutToDisappear backgroundColor:' + this.color);
2116  }
2117
2118  build() {
2119    Column()
2120      .width('100%')
2121      .height('100%')
2122      .backgroundColor(this.color)
2123  }
2124}
2125```
2126
2127### 示例12(设置TabBar平移距离和不透明度)
2128
2129本示例通过setTabBarTranslate、setTabBarOpacity等接口设置了TabBar的平移距离和不透明度。
2130
2131```ts
2132// xxx.ets
2133@Entry
2134@Component
2135struct TabsExample {
2136  private controller: TabsController = new TabsController();
2137
2138  build() {
2139    Column() {
2140      Button('设置TabBar的平移距离').margin({ top: 20 })
2141        .onClick(() => {
2142          this.controller.setTabBarTranslate({ x: -20, y: -20 });
2143        })
2144
2145      Button('设置TabBar的透明度').margin({ top: 20 })
2146        .onClick(() => {
2147          this.controller.setTabBarOpacity(0.5);
2148        })
2149
2150      Tabs({ barPosition: BarPosition.End, controller: this.controller }) {
2151        TabContent() {
2152          Column().width('100%').height('100%').backgroundColor('#00CB87')
2153        }.tabBar(BottomTabBarStyle.of($r('app.media.startIcon'), 'green'))
2154
2155        TabContent() {
2156          Column().width('100%').height('100%').backgroundColor('#007DFF')
2157        }.tabBar(BottomTabBarStyle.of($r('app.media.startIcon'), 'blue'))
2158
2159        TabContent() {
2160          Column().width('100%').height('100%').backgroundColor('#FFBF00')
2161        }.tabBar(BottomTabBarStyle.of($r('app.media.startIcon'), 'yellow'))
2162
2163        TabContent() {
2164          Column().width('100%').height('100%').backgroundColor('#E67C92')
2165        }.tabBar(BottomTabBarStyle.of($r('app.media.startIcon'), 'pink'))
2166      }
2167      .width(360)
2168      .height(296)
2169      .margin({ top: 20 })
2170      .barBackgroundColor('#F1F3F5')
2171    }
2172    .width('100%')
2173  }
2174}
2175```
2176
2177![tabs12](figures/tabBar_translate_opacity.gif)
2178
2179### 示例13(页面懒加载和释放)
2180
2181本示例通过使用自定义TabBar与Swiper配合LazyForEach实现页面懒加载和释放。
2182
2183```ts
2184// xxx.ets
2185class MyDataSource implements IDataSource {
2186  private list: number[] = [];
2187
2188  constructor(list: number[]) {
2189    this.list = list;
2190  }
2191
2192  totalCount(): number {
2193    return this.list.length;
2194  }
2195
2196  getData(index: number): number {
2197    return this.list[index];
2198  }
2199
2200  registerDataChangeListener(listener: DataChangeListener): void {
2201  }
2202
2203  unregisterDataChangeListener() {
2204  }
2205}
2206
2207@Entry
2208@Component
2209struct TabsSwiperExample {
2210  @State fontColor: string = '#182431';
2211  @State selectedFontColor: string = '#007DFF';
2212  @State currentIndex: number = 0;
2213  private list: number[] = [];
2214  private tabsController: TabsController = new TabsController();
2215  private swiperController: SwiperController = new SwiperController();
2216  private swiperData: MyDataSource = new MyDataSource([]);
2217
2218  aboutToAppear(): void {
2219    for (let i = 0; i <= 9; i++) {
2220      this.list.push(i);
2221    }
2222    this.swiperData = new MyDataSource(this.list);
2223  }
2224
2225  @Builder tabBuilder(index: number, name: string) {
2226    Column() {
2227      Text(name)
2228        .fontColor(this.currentIndex === index ? this.selectedFontColor : this.fontColor)
2229        .fontSize(16)
2230        .fontWeight(this.currentIndex === index ? 500 : 400)
2231        .lineHeight(22)
2232        .margin({ top: 17, bottom: 7 })
2233      Divider()
2234        .strokeWidth(2)
2235        .color('#007DFF')
2236        .opacity(this.currentIndex === index ? 1 : 0)
2237    }.width('20%')
2238  }
2239
2240  build() {
2241    Column() {
2242      Tabs({ barPosition: BarPosition.Start, controller: this.tabsController }) {
2243        ForEach(this.list, (item: number) => {
2244          TabContent().tabBar(this.tabBuilder(item, '页签 ' + this.list[item]))
2245        })
2246      }
2247      .onTabBarClick((index: number) => {
2248        this.currentIndex = index;
2249        this.swiperController.changeIndex(index, true);
2250      })
2251      .barMode(BarMode.Scrollable)
2252      .backgroundColor('#F1F3F5')
2253      .height(56)
2254      .width('100%')
2255
2256      Swiper(this.swiperController) {
2257        LazyForEach(this.swiperData, (item: string) => {
2258          Text(item.toString())
2259            .onAppear(()=>{
2260              console.info('onAppear ' + item.toString());
2261            })
2262            .onDisAppear(()=>{
2263              console.info('onDisAppear ' + item.toString());
2264            })
2265            .width('100%')
2266            .height('100%')
2267            .backgroundColor(0xAFEEEE)
2268            .textAlign(TextAlign.Center)
2269            .fontSize(30)
2270        }, (item: string) => item)
2271      }
2272      .loop(false)
2273      .onChange((index: number) => {
2274        this.currentIndex = index;
2275      })
2276      .onAnimationStart((index: number, targetIndex: number, extraInfo: SwiperAnimationEvent) => {
2277        this.currentIndex = targetIndex;
2278        this.tabsController.changeIndex(targetIndex);
2279      })
2280    }
2281  }
2282}
2283```
2284
2285![tabs13](figures/tabs_swiper_lazyForEach.gif)
2286
2287### 示例14(设置翻页动效)
2288
2289本示例通过设置animationMode属性,实现了翻页的动效。
2290
2291```ts
2292// xxx.ets
2293@Entry
2294@Component
2295struct TabsExample {
2296  @State currentIndex: number = 0;
2297  @State currentAnimationMode: AnimationMode = AnimationMode.CONTENT_FIRST;
2298  private controller: TabsController = new TabsController();
2299  private data: number[] = [];
2300
2301  aboutToAppear(): void {
2302    for (let i = 0; i < 10; i++) {
2303      this.data.push(i);
2304    }
2305  }
2306
2307  @Builder
2308  tabBuilder(title: string,targetIndex: number) {
2309    Column(){
2310      Text(title).fontColor(this.currentIndex === targetIndex ? '#FF0000' : '#6B6B6B')
2311    }.width('100%')
2312    .height(50)
2313    .justifyContent(FlexAlign.Center)
2314  }
2315
2316  build() {
2317    Column() {
2318      Tabs({ barPosition: BarPosition.End, controller: this.controller, index: this.currentIndex }) {
2319        ForEach(this.data, (item: string) => {
2320          TabContent() {
2321            Column(){
2322              Text('' + item)
2323            }.width('100%').height('100%').backgroundColor('#00CB87').justifyContent(FlexAlign.Center)
2324          }.tabBar(this.tabBuilder('P' + item, parseInt(item)))
2325        }, (item: string) => item)
2326      }
2327      .barWidth(360)
2328      .barHeight(60)
2329      .animationMode(this.currentAnimationMode)
2330      .animationDuration(4000)
2331      .onChange((index: number) => {
2332        this.currentIndex = index;
2333      })
2334      .width(360)
2335      .height(120)
2336      .backgroundColor('#F1F3F5')
2337
2338      Text('AnimationMode:' + AnimationMode[this.currentAnimationMode])
2339
2340      Button('AnimationMode').width('50%').margin({ top: 1 }).height(25)
2341        .onClick(()=>{
2342          if (this.currentAnimationMode === AnimationMode.CONTENT_FIRST) {
2343            this.currentAnimationMode = AnimationMode.ACTION_FIRST;
2344          } else if (this.currentAnimationMode === AnimationMode.ACTION_FIRST) {
2345            this.currentAnimationMode = AnimationMode.NO_ANIMATION;
2346          } else if (this.currentAnimationMode === AnimationMode.NO_ANIMATION) {
2347            this.currentAnimationMode = AnimationMode.CONTENT_FIRST_WITH_JUMP;
2348          } else if (this.currentAnimationMode === AnimationMode.CONTENT_FIRST_WITH_JUMP) {
2349            this.currentAnimationMode = AnimationMode.ACTION_FIRST_WITH_JUMP;
2350          } else if (this.currentAnimationMode === AnimationMode.ACTION_FIRST_WITH_JUMP) {
2351            this.currentAnimationMode = AnimationMode.CONTENT_FIRST;
2352          }
2353        })
2354    }.width('100%')
2355  }
2356}
2357```
2358
2359![tabs14](figures/tabs_animationMode.gif)
2360
2361### 示例15(页签超出TabBar区域显示)
2362
2363本示例通过使用barModifier设置tabBar的clip属性实现页签超出tabBar区域显示效果。
2364
2365```ts
2366// xxx.ets
2367import { CommonModifier } from '@kit.ArkUI';
2368
2369@Entry
2370@Component
2371struct TabsBarModifierExample {
2372  @State selectedIndex: number = 2;
2373  @State currentIndex: number = 2;
2374  @State isClip: boolean = false;
2375  @State tabBarModifier: CommonModifier = new CommonModifier();
2376  private controller: TabsController = new TabsController();
2377
2378  aboutToAppear(): void {
2379    this.tabBarModifier.clip(this.isClip);
2380  }
2381
2382  @Builder
2383  tabBuilder(title: string, targetIndex: number) {
2384    Column() {
2385      Image($r('app.media.startIcon')).width(30).height(30)
2386      Text(title).fontColor(this.selectedIndex === targetIndex ? '#1698CE' : '#6B6B6B')
2387    }.width('100%')
2388    .height(50)
2389    .justifyContent(FlexAlign.Center)
2390    .offset({ y: this.selectedIndex === targetIndex ? -15 : 0 })
2391  }
2392
2393  build() {
2394    Column() {
2395      Tabs({
2396        barPosition: BarPosition.End,
2397        index: this.currentIndex,
2398        controller: this.controller,
2399        barModifier: this.tabBarModifier
2400      }) {
2401        TabContent() {
2402          Column() {
2403            Text('首页的内容')
2404          }.width('100%').height('100%').backgroundColor('#00CB87').justifyContent(FlexAlign.Center)
2405        }.tabBar(this.tabBuilder('首页', 0))
2406
2407        TabContent() {
2408          Column() {
2409            Text('发现的内容')
2410          }.width('100%').height('100%').backgroundColor('#007DFF').justifyContent(FlexAlign.Center)
2411        }.tabBar(this.tabBuilder('发现', 1))
2412
2413        TabContent() {
2414          Column() {
2415            Text('推荐的内容')
2416          }.width('100%').height('100%').backgroundColor('#FFBF00').justifyContent(FlexAlign.Center)
2417        }.tabBar(this.tabBuilder('推荐', 2))
2418
2419        TabContent() {
2420          Column() {
2421            Text('我的内容')
2422          }.width('100%').height('100%').backgroundColor('#E67C92').justifyContent(FlexAlign.Center)
2423        }.tabBar(this.tabBuilder('我的', 3))
2424      }
2425      .vertical(false)
2426      .barMode(BarMode.Fixed)
2427      .barWidth(340)
2428      .barHeight(60)
2429      .onChange((index: number) => {
2430        this.currentIndex = index;
2431        this.selectedIndex = index;
2432      })
2433      .width(340)
2434      .height(400)
2435      .backgroundColor('#F1F3F5')
2436      .scrollable(true)
2437
2438      Button('isClip: ' + this.isClip)
2439        .margin({ top: 30 })
2440        .onClick(() => {
2441          this.isClip = !this.isClip;
2442          this.tabBarModifier.clip(this.isClip);
2443        })
2444    }.width('100%')
2445  }
2446}
2447```
2448
2449![tabs15](figures/tabs_barModifier_clip.gif)
2450
2451### 示例16(页签对齐布局)
2452
2453本示例通过使用barModifier设置tabBar的align属性实现页签对齐布局效果。
2454
2455```ts
2456// xxx.ets
2457import { CommonModifier } from '@kit.ArkUI';
2458
2459@Entry
2460@Component
2461struct TabsBarModifierExample {
2462  private controller: TabsController = new TabsController();
2463  @State text: string = '文本';
2464  @State isVertical: boolean = false;
2465  @State tabBarModifier: CommonModifier = new CommonModifier();
2466
2467  build() {
2468    Column() {
2469      Row() {
2470        Button('Alignment.Start ')
2471          .width('47%')
2472          .height(50)
2473          .margin({ top: 5 })
2474          .onClick((event?: ClickEvent) => {
2475            this.tabBarModifier.align(Alignment.Start);
2476          })
2477          .margin({ right: '6%', bottom: '12vp' })
2478        Button('Alignment.End')
2479          .width('47%')
2480          .height(50)
2481          .margin({ top: 5 })
2482          .onClick((event?: ClickEvent) => {
2483            this.tabBarModifier.align(Alignment.End);
2484          })
2485          .margin({ bottom: '12vp' })
2486      }
2487
2488      Row() {
2489        Button('Alignment.Center')
2490          .width('47%')
2491          .height(50)
2492          .margin({ top: 5 })
2493          .onClick((event?: ClickEvent) => {
2494            this.tabBarModifier.align(Alignment.Center);
2495          })
2496          .margin({ right: '6%', bottom: '12vp' })
2497        Button('isVertical: ' + this.isVertical)
2498          .width('47%')
2499          .height(50)
2500          .margin({ top: 5 })
2501          .onClick((event?: ClickEvent) => {
2502            this.isVertical = !this.isVertical;
2503          })
2504          .margin({ bottom: '12vp' })
2505      }
2506
2507      Row() {
2508        Button('Alignment.Top')
2509          .width('47%')
2510          .height(50)
2511          .margin({ top: 5 })
2512          .onClick((event?: ClickEvent) => {
2513            this.tabBarModifier.align(Alignment.Top);
2514          })
2515          .margin({ right: '6%', bottom: '12vp' })
2516        Button('Alignment.Bottom')
2517          .width('47%')
2518          .height(50)
2519          .margin({ top: 5 })
2520          .onClick((event?: ClickEvent) => {
2521            this.tabBarModifier.align(Alignment.Bottom);
2522          })
2523          .margin({ bottom: '12vp' })
2524      }
2525
2526      Tabs({ barPosition: BarPosition.End, controller: this.controller, barModifier: this.tabBarModifier }) {
2527        TabContent() {
2528          Column().width('100%').height('100%').backgroundColor(Color.Pink)
2529        }.tabBar(SubTabBarStyle.of(this.text))
2530
2531        TabContent() {
2532          Column().width('100%').height('100%').backgroundColor(Color.Green)
2533        }.tabBar(SubTabBarStyle.of(this.text))
2534
2535        TabContent() {
2536          Column().width('100%').height('100%').backgroundColor(Color.Blue)
2537        }.tabBar(SubTabBarStyle.of(this.text))
2538      }
2539      .vertical(this.isVertical)
2540      .height('60%')
2541      .backgroundColor(0xf1f3f5)
2542      .barMode(BarMode.Scrollable)
2543    }
2544    .width('100%')
2545    .height(500)
2546    .margin({ top: 5 })
2547    .padding('24vp')
2548  }
2549}
2550```
2551
2552![tabs16](figures/tabs_barModifier_align.gif)
2553
2554### 示例17(Tabs与TabBar联动切换)
2555
2556该示例通过onSelected接口,实现了Tabs与TabBar联动切换。
2557
2558```ts
2559// xxx.ets
2560@Entry
2561@Component
2562struct TabsExample {
2563  @State fontColor: string = '#182431';
2564  @State selectedFontColor: string = '#007DFF';
2565  @State currentIndex: number = 0;
2566  @State selectedIndex: number = 0;
2567  private controller: TabsController = new TabsController();
2568
2569  @Builder tabBuilder(index: number, name: string) {
2570    Column() {
2571      Text(name)
2572        .fontColor(this.selectedIndex === index ? this.selectedFontColor : this.fontColor)
2573        .fontSize(16)
2574        .fontWeight(this.selectedIndex === index ? 500 : 400)
2575        .lineHeight(22)
2576        .margin({ top: 17, bottom: 7 })
2577      Divider()
2578        .strokeWidth(2)
2579        .color('#007DFF')
2580        .opacity(this.selectedIndex === index ? 1 : 0)
2581    }.width('100%')
2582  }
2583
2584  build() {
2585    Column() {
2586      Tabs({ barPosition: BarPosition.Start, index: this.currentIndex, controller: this.controller }) {
2587        TabContent() {
2588          Column().width('100%').height('100%').backgroundColor('#00CB87')
2589        }.tabBar(this.tabBuilder(0, 'green'))
2590
2591        TabContent() {
2592          Column().width('100%').height('100%').backgroundColor('#007DFF')
2593        }.tabBar(this.tabBuilder(1, 'blue'))
2594
2595        TabContent() {
2596          Column().width('100%').height('100%').backgroundColor('#FFBF00')
2597        }.tabBar(this.tabBuilder(2, 'yellow'))
2598
2599        TabContent() {
2600          Column().width('100%').height('100%').backgroundColor('#E67C92')
2601        }.tabBar(this.tabBuilder(3, 'pink'))
2602      }
2603      .vertical(false)
2604      .barMode(BarMode.Fixed)
2605      .barWidth(360)
2606      .barHeight(56)
2607      .animationDuration(400)
2608      .animationMode(AnimationMode.CONTENT_FIRST)
2609      .onChange((index: number) => {
2610        console.info('onChange index:' + index);
2611        this.currentIndex = index;
2612      })
2613      .onSelected((index: number) => {
2614        console.info('onSelected index:' + index);
2615        this.selectedIndex = index;
2616      })
2617      .onUnselected((index: number) => {
2618        console.info('onUnselected index:' + index);
2619      })
2620      .width('100%')
2621      .height('100%')
2622      .backgroundColor('#F1F3F5')
2623    }.width('100%')
2624  }
2625}
2626```
2627![tabs17](figures/tabs_tarbar.gif)
2628
2629### 示例18(释放Tabs子组件)
2630
2631该示例通过设置cachedMaxCount属性,实现了Tabs子组件的释放。
2632
2633```ts
2634@Entry
2635@Component
2636struct TabsExample {
2637  build() {
2638    Tabs() {
2639      TabContent() {
2640        MyComponent({ color: '#00CB87' })
2641      }.tabBar(SubTabBarStyle.of('green'))
2642
2643      TabContent() {
2644        MyComponent({ color: '#007DFF' })
2645      }.tabBar(SubTabBarStyle.of('blue'))
2646
2647      TabContent() {
2648        MyComponent({ color: '#FFBF00' })
2649      }.tabBar(SubTabBarStyle.of('yellow'))
2650
2651      TabContent() {
2652        MyComponent({ color: '#E67C92' })
2653      }.tabBar(SubTabBarStyle.of('pink'))
2654    }
2655    .width(360)
2656    .height(296)
2657    .backgroundColor('#F1F3F5')
2658    .cachedMaxCount(1, TabsCacheMode.CACHE_BOTH_SIDE)
2659  }
2660}
2661
2662@Component
2663struct MyComponent {
2664  private color: string = '';
2665
2666  aboutToAppear(): void {
2667    console.info('aboutToAppear backgroundColor:' + this.color);
2668  }
2669
2670  aboutToDisappear(): void {
2671    console.info('aboutToDisappear backgroundColor:' + this.color);
2672  }
2673
2674  build() {
2675    Column()
2676      .width('100%')
2677      .height('100%')
2678      .backgroundColor(this.color)
2679  }
2680}
2681```
2682
2683### 示例19(设置TabBar背景模糊效果)
2684
2685该示例分别通过barBackgroundBlurStyle和barBackgroundEffect设置TabsBar页签栏的背景模糊效果。
2686
2687```ts
2688// xxx.ets
2689@Entry
2690@Component
2691struct TabsExample {
2692  build() {
2693    Column() {
2694      // barBackgroundBlurStyle 可以通过枚举值的方式设置模糊参数
2695      Stack() {
2696        Image($r('app.media.startIcon'))
2697        Tabs() {
2698          TabContent() {
2699            Column().width('100%').height('100%').backgroundColor('#00CB87')
2700          }.tabBar('green')
2701
2702          TabContent() {
2703            Column().width('100%').height('100%').backgroundColor('#007DFF')
2704          }.tabBar('blue')
2705
2706          TabContent() {
2707            Column().width('100%').height('100%').backgroundColor('#FFBF00')
2708          }.tabBar('yellow')
2709
2710          TabContent() {
2711            Column().width('100%').height('100%').backgroundColor('#E67C92')
2712          }.tabBar('pink')
2713        }
2714        .barBackgroundBlurStyle(BlurStyle.COMPONENT_THICK,
2715          { colorMode: ThemeColorMode.LIGHT, adaptiveColor: AdaptiveColor.DEFAULT, scale: 1.0 })
2716      }
2717      .width(300)
2718      .height(300)
2719      .margin(10)
2720
2721      // barBackgroundEffect 可以自定义设置tabBar页签栏的模糊半径、亮度、饱和度等参数
2722      Stack() {
2723        Image($r('app.media.startIcon'))
2724        Tabs() {
2725          TabContent() {
2726            Column().width('100%').height('100%').backgroundColor('#00CB87')
2727          }.tabBar('green')
2728
2729          TabContent() {
2730            Column().width('100%').height('100%').backgroundColor('#007DFF')
2731          }.tabBar('blue')
2732
2733          TabContent() {
2734            Column().width('100%').height('100%').backgroundColor('#FFBF00')
2735          }.tabBar('yellow')
2736
2737          TabContent() {
2738            Column().width('100%').height('100%').backgroundColor('#E67C92')
2739          }.tabBar('pink')
2740        }
2741        .barBackgroundEffect({ radius: 20, brightness: 0.6, saturation: 15 })
2742      }
2743      .width(300)
2744      .height(300)
2745      .margin(10)
2746    }
2747  }
2748}
2749```
2750![tabs19](figures/tabBar_backgroud.png)
2751
2752### 示例20(设置边缘滑动效果)
2753
2754该示例通过edgeEffect实现不同边缘滑动效果。
2755
2756```ts
2757// xxx.ets
2758@Entry
2759@Component
2760struct TabsExample {
2761  @State edgeEffect: EdgeEffect = EdgeEffect.Spring;
2762
2763  build() {
2764    Column() {
2765      Tabs() {
2766        TabContent() {
2767          Column().width('100%').height('100%').backgroundColor('#00CB87')
2768        }.tabBar('green')
2769
2770        TabContent() {
2771          Column().width('100%').height('100%').backgroundColor('#007DFF')
2772        }.tabBar('blue')
2773
2774        TabContent() {
2775          Column().width('100%').height('100%').backgroundColor('#FFBF00')
2776        }.tabBar('yellow')
2777
2778        TabContent() {
2779          Column().width('100%').height('100%').backgroundColor('#E67C92')
2780        }.tabBar('pink')
2781      }
2782      .width(360)
2783      .height(296)
2784      .margin({ top: 52 })
2785      .backgroundColor('#F1F3F5')
2786      .edgeEffect(this.edgeEffect)
2787
2788      Button('EdgeEffect.Spring').width('50%').margin({ top: 20 })
2789        .onClick(() => {
2790          this.edgeEffect = EdgeEffect.Spring;
2791        })
2792
2793      Button('EdgeEffect.Fade').width('50%').margin({ top: 20 })
2794        .onClick(() => {
2795          this.edgeEffect = EdgeEffect.Fade;
2796        })
2797
2798      Button('EdgeEffect.None').width('50%').margin({ top: 20 })
2799        .onClick(() => {
2800          this.edgeEffect = EdgeEffect.None;
2801        })
2802    }.width('100%')
2803  }
2804}
2805```
2806![tabs20](figures/tabs_edges_slide.gif)
2807
2808### 示例21(Tabs设置翻页动画曲线)
2809
2810该示例展示了如何通过animationCurve接口设置Tabs翻页动画曲线,并结合animationDuration设置翻页动画的时长。
2811
2812```ts
2813import { curves } from '@kit.ArkUI';
2814
2815interface TabsItemType { text: string, backgroundColor: ResourceColor }
2816
2817@Entry
2818@Component
2819struct TabsExample {
2820  private tabsController: TabsController = new TabsController();
2821  private curves: (Curve | ICurve) [] = [
2822    curves.interpolatingSpring(-1, 1, 328, 34),
2823    curves.springCurve(10, 1, 228, 30),
2824    curves.cubicBezierCurve(0.25, 0.1, 0.25, 1.0),
2825  ];
2826  @State curveIndex: number = 0;
2827  private datas: TabsItemType[] = [
2828    { text: '1', backgroundColor: '#004AAF' },
2829    { text: '2', backgroundColor: '#2787D9' },
2830    { text: '3', backgroundColor: '#D5D5D5' },
2831    { text: '4', backgroundColor: '#707070' },
2832    { text: '5', backgroundColor: '#F7F7F7' },
2833  ];
2834  @State duration: number = 0;
2835
2836  build() {
2837    Column({ space:2 }) {
2838      Tabs({ controller: this.tabsController }) {
2839        ForEach(this.datas, (item: TabsItemType, index: number) => {
2840          TabContent() {}
2841          .tabBar(item.text)
2842          .backgroundColor(item.backgroundColor)
2843        })
2844      }
2845      .backgroundColor(0xf1f3f5)
2846      .width('100%')
2847      .height(500)
2848      .animationCurve(this.curves[this.curveIndex])
2849      .animationDuration(this.duration)
2850      Row({ space:2 }) {
2851        Text('Curve:' + this.curveIndex)
2852        Button('++').onClick(() => { this.curveIndex = (this.curveIndex + 1) % this.curves.length; })
2853        Button('reset').onClick(() => { this.curveIndex = 0; })
2854      }
2855      .margin({ left: '10vp' })
2856      .width('100%')
2857      Row({ space:2 }) {
2858        Text('Duration:' + this.duration)
2859        Button('+100').onClick(() => { this.duration = (this.duration + 100) % 10000; })
2860        Button('+1000').onClick(() => { this.duration = (this.duration + 1000) % 10000; })
2861        Button('reset').onClick(() => { this.duration = 0; })
2862      }
2863      .margin({ left: '10vp' })
2864      .width('100%')
2865    }
2866    .margin('10vp')
2867  }
2868}
2869```
2870![tabs_curve](figures/tabs_curve.gif)
2871