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.Fixed。 132 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.Scrollable。 148 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) \| [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对象说明) \| 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<EdgeEffect>) 395 396设置边缘回弹效果。 397 398**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 399 400**系统能力:** SystemCapability.ArkUI.ArkUI.Full 401 402**参数:** 403 404| 参数名 | 类型 | 必填 | 说明 | 405| ------ | --------------------------------------------- | ---- | -------------------------------------------- | 406| edgeEffect | Optional<[EdgeEffect](ts-appendix-enums.md#edgeeffect)> | 是 | 边缘滑动效果。<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) \| 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 2871