鸿蒙ArkUI---基础组件Tabs(Tabbar)
基础页面组件
Tabs
作用:
快速创建Tabbar
个人理解:
快速的创建Tabar。
效果图:
代码:interface TabItem {icon: Resource; //未选中activeIcon: Resource; //选中name: string; //文字 }@Entry @Component struct Index {// struct Index 数据tabList: TabItem[] = [{icon: $r('XXX'),activeIcon: $r('XXX'),name: 'XXX'},{icon: $r('XXX'),activeIcon: $r('XXX'),name: 'XX'},{icon: $r('XXX'),activeIcon: $r('XXX'),name: 'XX'},{icon: $r('XXX'),activeIcon: $r('XXX'),name: 'XX'}]@StorageProp('bottomHeight') bottomHeight: number = 0@StateactiveIndex: number = 0@BuilderTabbarBuilder(item: TabItem, index: number) {Column({ space: 5 }) {Image(this.activeIndex == index ? item.activeIcon : item.icon).width(24).aspectRatio(1) // 设置宽高比,保证图片展示一致Text(item.name).fontSize(12).fontColor(this.activeIndex == index ? '#131313' : '#979797')}}build() {Column() {Tabs() {ForEach(this.tabList, (item: TabItem, index: number) => {TabContent() {// 根据不同的下标->渲染对应的组件if (index == 0) {XXX// 第一个按钮对应的内容(创建相应的Page)} else if (index == 1) {XXX// 第二个按钮对应的内容(创建相应的Page)} else if (index == 2) {XXX// 第三个按钮对应的内容(创建相应的Page)} else {XXX// 第四个按钮对应的内容(创建相应的Page)}}.tabBar(this.TabbarBuilder(item, index))})}.barPosition(BarPosition.End) // Tabbar位置在屏幕下方.scrollable(false) // 不开启滑屏效果.onTabBarClick((index) => {this.activeIndex = index})}.width('100%').height('100%').backgroundColor('#ffffff').padding({bottom: this.bottomHeight // 全屏模式下,不占用安全区位置})} }
官方说明:
Tabs
更新时间: 2025-06-25 13:58
通过页签进行内容视图切换的容器组件,每个页签对应一个内容视图。
说明
该组件从API version 7开始支持。后续版本如有新增内容,则采用上角标单独标记该内容的起始版本。
该组件从API version 11开始默认支持安全区避让特性(默认值为:expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.BOTTOM])),开发者可以重写该属性覆盖默认行为,API version 11之前的版本需配合expandSafeArea属性实现安全区避让。
子组件
支持设备PhonePC/2in1TabletWearable
不支持自定义组件作为子组件,仅可包含子组件TabContent,以及渲染控制类型if/else和ForEach,并且if/else和ForEach下也仅支持TabContent,不支持自定义组件。
说明
Tabs子组件的visibility属性设置为None,或者visibility属性设置为Hidden时,对应子组件不显示,但依然会在视窗内占位。
Tabs子组件TabContent显示之后不会销毁,若需要页面懒加载和释放,可以参考示例13。
接口
支持设备PhonePC/2in1TabletWearable
Tabs(options?: TabsOptions)
创建Tabs容器。
元服务API: 从API version 11开始,该接口支持在元服务中使用。
系统能力: SystemCapability.ArkUI.ArkUI.Full
参数:
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
options | TabsOptions | 否 | Tabs组件参数。 |
TabsOptions
支持设备PhonePC/2in1TabletWearable
Tabs组件参数,设置Tabs的页签位置,当前显示页签的索引,Tabs控制器和TabBar的通用属性。
系统能力: SystemCapability.ArkUI.ArkUI.Full
名称 | 类型 | 必填 | 说明 |
---|---|---|---|
barPosition | BarPosition | 否 | 设置Tabs的页签位置。 默认值:BarPosition.Start。 元服务API: 从API version 11开始,该接口支持在元服务中使用。 |
index | number | 否 | 设置当前显示页签的索引。 默认值:0 说明: 设置为小于0的值时按默认值显示。 可选值为[0, TabContent子节点数量-1]。 直接修改index跳页时,切换动效不生效。 使用TabController的changeIndex时,默认生效切换动效,可以设置animationDuration为0关闭动画。 从API version 10开始,该参数支持$$双向绑定变量。 Tabs重建、系统资源切换(如系统字体切换、系统深浅色切换)或者组件属性变化时,会跳转到index对应的页面。若需要在上述情况下不跳转,建议使用双向绑定。 元服务API: 从API version 11开始,该接口支持在元服务中使用。 |
controller | TabsController | 否 | 设置Tabs控制器。 元服务API: 从API version 11开始,该接口支持在元服务中使用。 |
barModifier | CommonModifier | 否 | 设置TabBar的通用属性。 说明: 动态置为undefined时会保持当前状态不变,不会重置各通用属性。 由一个CommonModifier切换为另一个CommonModifier时,重复属性会进行覆盖,非重复属性会同时生效,不会重置前一个CommonModifier的通用属性。 Tabs的barWidth、barHeight、barBackgroundColor、barBackgroundBlurStyle、barBackgroundEffect属性会覆盖CommonModifier的width、height、backgroundColor、backgroundBlurStyle、backgroundEffect属性。 align属性仅在BarMode.Scrollable模式下生效,且Tabs为横向时还需nonScrollableLayoutStyle未设置或设置为异常值时才能生效。 TabContent组件的tabBar属性为底部页签样式时不支持拖拽功能。 元服务API: 从API version 15开始,该接口支持在元服务中使用。 |
BarPosition枚举说明
支持设备PhonePC/2in1TabletWearable
Tabs页签位置枚举。
元服务API: 从API version 11开始,该接口支持在元服务中使用。
系统能力: SystemCapability.ArkUI.ArkUI.Full
名称 | 说明 |
---|---|
Start | vertical属性方法设置为true时,页签位于容器左侧;vertical属性方法设置为false时,页签位于容器顶部。 |
End | vertical属性方法设置为true时,页签位于容器右侧;vertical属性方法设置为false时,页签位于容器底部。 |
属性
支持设备PhonePC/2in1TabletWearable
除支持通用属性外,还支持以下属性:
vertical
支持设备PhonePC/2in1TabletWearable
vertical(value: boolean)
设置是否为纵向Tab。
元服务API: 从API version 11开始,该接口支持在元服务中使用。
系统能力: SystemCapability.ArkUI.ArkUI.Full
参数:
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
value | boolean | 是 | 是否为纵向Tab。 默认值:false,横向Tabs,为true时纵向Tabs。 当横向Tabs设置height为auto时,Tabs组件高度自适应子组件高度,即为tabBar高度+divider线宽+TabContent高度+上下padding值+上下border宽度。 当纵向Tabs设置width为auto时,Tabs组件宽度自适应子组件宽度,即为tabBar宽度+divider线宽+TabContent宽度+左右padding值+左右border宽度。 尽量保持每一个页面中的子组件尺寸大小一致,避免滑动页面时出现页面切换动画跳动现象。 |
scrollable
支持设备PhonePC/2in1TabletWearable
scrollable(value: boolean)
设置是否可以通过滑动页面进行页面切换。
元服务API: 从API version 11开始,该接口支持在元服务中使用。
系统能力: SystemCapability.ArkUI.ArkUI.Full
参数:
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
value | boolean | 是 | 是否可以通过滑动页面进行页面切换。 默认值:true,可以通过滑动页面进行页面切换。为false时不可滑动切换页面。 |
barMode
支持设备PhonePC/2in1TabletWearable
barMode(value: BarMode, options?: ScrollableBarModeOptions)
设置TabBar布局模式。
元服务API: 从API version 11开始,该接口支持在元服务中使用。
系统能力: SystemCapability.ArkUI.ArkUI.Full
参数:
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
value | BarMode | 是 | 布局模式。 默认值:BarMode.Fixed |
options | ScrollableBarModeOptions | 否 | Scrollable模式下的TabBar的布局样式。 说明: 仅Scrollable且水平模式下有效。 |
barMode
支持设备PhonePC/2in1TabletWearable
barMode(value: BarMode.Fixed)
设置TabBar布局模式为BarMode.Fixed。
元服务API: 从API version 11开始,该接口支持在元服务中使用。
系统能力: SystemCapability.ArkUI.ArkUI.Full
参数:
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
value | BarMode.Fixed | 是 | 所有TabBar会平均分配barWidth宽度(纵向时平均分配barHeight高度)。 |
barMode
支持设备PhonePC/2in1TabletWearable
barMode(value: BarMode.Scrollable, options: ScrollableBarModeOptions)
设置TabBar布局模式为BarMode.Scrollable。
元服务API: 从API version 11开始,该接口支持在元服务中使用。
系统能力: SystemCapability.ArkUI.ArkUI.Full
参数:
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
value | BarMode.Scrollable | 是 | 所有TabBar都使用实际布局宽度,超过总宽度(横向Tabs的barWidth,纵向Tabs的barHeight)后可滑动。 |
options | ScrollableBarModeOptions | 是 | Scrollable模式下的TabBar的布局样式。 说明: 仅水平模式下有效。 |
barWidth
支持设备PhonePC/2in1TabletWearable
barWidth(value: Length)
设置TabBar的宽度值。设置为小于0或大于Tabs宽度值时,按默认值显示。
元服务API: 从API version 11开始,该接口支持在元服务中使用。
系统能力: SystemCapability.ArkUI.ArkUI.Full
参数:
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
value | Length | 是 | TabBar的宽度值。 默认值: 未设置SubTabBarStyle和BottomTabBarStyle的TabBar且vertical属性为false时,默认值为Tabs的宽度。 未设置SubTabBarStyle和BottomTabBarStyle的TabBar且vertical属性为true时,默认值为56vp。 设置SubTabBarStyle样式且vertical属性为false时,默认值为Tabs的宽度。 设置SubTabBarStyle样式且vertical属性为true时,默认值为56vp。 设置BottomTabBarStyle样式且vertical属性为true时,默认值为96vp。 设置BottomTabBarStyle样式且vertical属性为false时,默认值为Tabs的宽度。 |
barHeight
支持设备PhonePC/2in1TabletWearable
barHeight(value: Length)
设置TabBar的高度值。横向Tabs可以设置height为'auto',让TabBar自适应子组件高度。height设置为小于0或大于Tabs高度值时,按默认值显示。
API version 14之前的版本,若设置barHeight为固定值后,TabBar无法扩展底部安全区。从API version 14开始支持配合safeAreaPadding属性,当safeAreaPadding不设置bottom或者bottom设置为0时,可以实现扩展安全区。
元服务API: 从API version 11开始,该接口支持在元服务中使用。
系统能力: SystemCapability.ArkUI.ArkUI.Full
参数:
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
value | Length | 是 | TabBar的高度值。 默认值: 未设置带样式的TabBar且vertical属性为false时,默认值为56vp。 未设置带样式的TabBar且vertical属性为true时,默认值为Tabs的高度。 设置SubTabBarStyle样式且vertical属性为false时,默认值为56vp。 设置SubTabBarStyle样式且vertical属性为true时,默认值为Tabs的高度。 设置BottomTabBarStyle样式且vertical属性为true时,默认值为Tabs的高度。 设置BottomTabBarStyle样式且vertical属性为false时,默认值为56vp,从API version 12开始,默认值变更为48vp。 |
barHeight
支持设备PhonePC/2in1TabletWearable
barHeight(height: Length, noMinHeightLimit: boolean)
设置TabBar的高度值。横向Tabs可以设置height为'auto',让TabBar自适应子组件高度,并通过设置noMinHeightLimit为true让自适应高度可以小于TabBar默认高度。height设置为小于0或大于Tabs高度值时,按默认值显示。
元服务API: 从API version 20开始,该接口支持在元服务中使用。
系统能力: SystemCapability.ArkUI.ArkUI.Full
参数:
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
height | Length | 是 | TabBar的高度值。 默认值: 未设置带样式的TabBar且vertical属性为false时,默认值为56vp。 未设置带样式的TabBar且vertical属性为true时,默认值为Tabs的高度。 设置SubTabBarStyle样式且vertical属性为false时,默认值为56vp。 设置SubTabBarStyle样式且vertical属性为true时,默认值为Tabs的高度。 设置BottomTabBarStyle样式且vertical属性为true时,默认值为Tabs的高度。 设置BottomTabBarStyle样式且vertical属性为false时,默认值为48vp。 |
noMinHeightLimit | boolean | 是 | height设置为'auto'时,设置是否取消TabBar的最小高度限制。默认值为false。 说明: 值为true表示取消TabBar的最小高度限制,即TabBar的高度值可以小于默认值。 值为false表示限制TabBar的最小高度,即TabBar的最小高度值等于默认值。 |
animationCurve
支持设备PhonePC/2in1TabletWearable
animationCurve(curve: Curve | ICurve)
设置Tabs翻页动画曲线。常用曲线参考Curve枚举说明,也可以通过插值计算模块提供的接口创建自定义的插值曲线对象。
元服务API: 从API version 20开始,该接口支持在元服务中使用。
系统能力: SystemCapability.ArkUI.ArkUI.Full
参数:
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
curve | Curve | ICurve | 是 | Tabs翻页的动画曲线。 默认值: 滑动TabContent翻页时,默认值为interpolatingSpring(-1, 1, 228, 30)。 点击TabBar页签和调用TabsController的changeIndex接口翻页时,默认值为cubicBezierCurve(0.2, 0.0, 0.1, 1.0)。 设置自定义动画曲线时,滑动翻页和点击页签、调用changeIndex翻页都使用设置的动画曲线。 |
animationDuration
支持设备PhonePC/2in1TabletWearable
animationDuration(value: number)
设置Tabs翻页动画时长。
animationCurve不设置时,由于滑动TabContent翻页动画曲线interpolatingSpring(-1, 1, 228, 30)时长只受曲线自身参数影响,animationDuration只能控制点击TabBar页签和调用TabsController的changeIndex接口切换TabContent的动画时长。
不受animationDuration控制的曲线可以查阅插值计算模块,比如springMotion、responsiveSpringMotion和interpolatingSpring类型的曲线。
元服务API: 从API version 11开始,该接口支持在元服务中使用。
系统能力: SystemCapability.ArkUI.ArkUI.Full
参数:
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
value | number | 是 | Tabs翻页的动画时长。 默认值: API version 10及以前,不设置该属性或设置为null时,默认值为0,即Tabs翻页无动画。设置为小于0或undefined时,默认值为300。 API version 11及以后,不设置该属性或设置为异常值,且设置TabBar为BottomTabBarStyle样式时,默认值为0。设置TabBar为其他样式时,默认值为300。 单位:ms 取值范围:[0, +∞) |
animationMode
支持设备PhonePC/2in1TabletWearable
animationMode(mode: Optional<AnimationMode>)
设置点击TabBar页签或调用TabsController的changeIndex接口时切换TabContent的动画形式。
元服务API: 从API version 12开始,该接口支持在元服务中使用。
系统能力: SystemCapability.ArkUI.ArkUI.Full
参数:
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
mode | Optional<AnimationMode> | 是 | 点击TabBar页签或调用TabsController的changeIndex接口时切换TabContent的动画形式。 默认值:AnimationMode.CONTENT_FIRST,表示在点击TabBar页签或调用TabsController的changeIndex接口切换TabContent时,先加载目标页内容,再开始切换动画。 |
barPosition
支持设备PhonePC/2in1TabletWearable
barPosition(value: BarPosition)
设置Tabs的页签位置。
元服务API: 从API version 11开始,该接口支持在元服务中使用。
系统能力: SystemCapability.ArkUI.ArkUI.Full
参数:
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
value | BarPosition | 是 | 设置Tabs的页签位置。 默认值:BarPosition.Start |
divider
支持设备PhonePC/2in1TabletWearable
divider(value: DividerStyle | null)
设置区分TabBar和TabContent的分割线样式。
元服务API: 从API version 11开始,该接口支持在元服务中使用。
系统能力: SystemCapability.ArkUI.ArkUI.Full
参数:
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
value | DividerStyle | null | 是 | 分割线样式,默认不显示分割线。 DividerStyle:分割线的样式; null:不显示分割线。 |
fadingEdge
支持设备PhonePC/2in1TabletWearable
fadingEdge(value: boolean)
设置页签超过容器宽度时是否渐隐消失。建议配合barBackgroundColor属性一起使用,如果barBackgroundColor属性没有定义,会默认显示页签末端为白色的渐隐效果。
元服务API: 从API version 11开始,该接口支持在元服务中使用。
系统能力: SystemCapability.ArkUI.ArkUI.Full
参数:
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
value | boolean | 是 | 页签超过容器宽度时是否渐隐消失。 默认值:true,页签超过容器宽度时会渐隐消失。设置为false时,页签超过容器宽度直接截断显示,不产生任何渐变效果。 |
barOverlap
支持设备PhonePC/2in1TabletWearable
barOverlap(value: boolean)
设置TabBar是否背后变模糊并叠加在TabContent之上。
元服务API: 从API version 11开始,该接口支持在元服务中使用。
系统能力: SystemCapability.ArkUI.ArkUI.Full
参数:
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
value | boolean | 是 | TabBar是否背后变模糊并叠加在TabContent之上。当barOverlap设置为true时,TabBar背后变模糊并叠加在TabContent之上,并且TabBar默认模糊材质的BlurStyle值修改为'BlurStyle.COMPONENT_THICK'。当barOverlap设置为false时,无模糊和叠加效果。 默认值:false |
barBackgroundColor
支持设备PhonePC/2in1TabletWearable
barBackgroundColor(value: ResourceColor)
设置TabBar的背景颜色。
元服务API: 从API version 11开始,该接口支持在元服务中使用。
系统能力: SystemCapability.ArkUI.ArkUI.Full
参数:
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
value | ResourceColor | 是 | TabBar的背景颜色。 默认值:Color.Transparent,透明 |
barBackgroundBlurStyle
支持设备PhonePC/2in1TabletWearable
barBackgroundBlurStyle(value: BlurStyle)
设置TabBar的背景模糊材质。
元服务API: 从API version 11开始,该接口支持在元服务中使用。
系统能力: SystemCapability.ArkUI.ArkUI.Full
参数:
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
value | BlurStyle | 是 | TabBar的背景模糊材质。 默认值:BlurStyle.NONE |
barBackgroundBlurStyle
支持设备PhonePC/2in1TabletWearable
barBackgroundBlurStyle(style: BlurStyle, options: BackgroundBlurStyleOptions)
为TabBar提供一种在背景和内容之间的模糊能力,通过枚举值的方式封装了不同的模糊半径、蒙版颜色、蒙版透明度、饱和度、亮度。
元服务API: 从API version 18开始,该接口支持在元服务中使用。
系统能力: SystemCapability.ArkUI.ArkUI.Full
参数:
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
style | BlurStyle | 是 | 背景模糊样式。模糊样式中封装了模糊半径、蒙版颜色、蒙版透明度、饱和度、亮度五个参数。 |
options | BackgroundBlurStyleOptions | 是 | 背景模糊选项。 |
barGridAlign
支持设备PhonePC/2in1TabletWearable
barGridAlign(value: BarGridColumnOptions)
以栅格化方式设置TabBar的可见区域。具体参见BarGridColumnOptions对象。仅水平模式下有效,不适用于XS、XL和XXL设备。
元服务API: 从API version 11开始,该接口支持在元服务中使用。
系统能力: SystemCapability.ArkUI.ArkUI.Full
参数:
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
value | BarGridColumnOptions | 是 | 以栅格化方式设置TabBar的可见区域。 |
edgeEffect
支持设备PhonePC/2in1TabletWearable
edgeEffect(edgeEffect: Optional<EdgeEffect>)
设置边缘回弹效果。
元服务API: 从API version 12开始,该接口支持在元服务中使用。
系统能力: SystemCapability.ArkUI.ArkUI.Full
参数:
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
edgeEffect | Optional<EdgeEffect> | 是 | 边缘滑动效果。 默认值:EdgeEffect.Spring |
barBackgroundEffect
支持设备PhonePC/2in1TabletWearable
barBackgroundEffect(options: BackgroundEffectOptions)
设置TabBar背景属性,包含背景模糊半径,亮度,饱和度,颜色等参数。
元服务API: 从API version 18开始,该接口支持在元服务中使用。
系统能力: SystemCapability.ArkUI.ArkUI.Full
参数:
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
options | BackgroundEffectOptions | 是 | 设置TabBar背景属性包括:模糊半径,亮度,饱和度,颜色等。 |
pageFlipMode
支持设备PhonePC/2in1TabletWearable
pageFlipMode(mode: Optional<PageFlipMode>)
设置鼠标滚轮翻页模式。
元服务API: 从API version 15开始,该接口支持在元服务中使用。
系统能力: SystemCapability.ArkUI.ArkUI.Full
参数:
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
mode | Optional<PageFlipMode> | 是 | 鼠标滚轮翻页模式。 默认值:PageFlipMode.CONTINUOUS |
cachedMaxCount
支持设备PhonePC/2in1TabletWearable
cachedMaxCount(count: number, mode: TabsCacheMode)
设置子组件的最大缓存个数和缓存模式。设置该属性后,不会对缓存范围内的子组件进行预加载,仅对缓存范围外的子组件进行释放。
元服务API: 从API version 19开始,该接口支持在元服务中使用。
系统能力: SystemCapability.ArkUI.ArkUI.Full
参数:
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
count | number | 是 | 子组件的最大缓存个数。默认所有子组件加载后都不再释放。 取值范围:[0, +∞)。 |
mode | TabsCacheMode | 是 | 子组件的缓存模式。 默认值:TabsCacheMode.CACHE_BOTH_SIDE |
DividerStyle对象说明
支持设备PhonePC/2in1TabletWearable
分割线样式对象。
元服务API: 从API version 11开始,该接口支持在元服务中使用。
系统能力: SystemCapability.ArkUI.ArkUI.Full
名称 | 类型 | 必填 | 说明 |
---|---|---|---|
strokeWidth | Length | 是 | 分割线的线宽(不支持百分比设置)。 默认值:0.0 单位:vp 取值范围:[0, +∞)。 |
color | ResourceColor | 否 | 分割线的颜色。 默认值:#33182431 |
startMargin | Length | 否 | 分割线与侧边栏顶端的距离(不支持百分比设置)。 默认值:0.0 单位:vp 取值范围:[0, +∞)。 |
endMargin | Length | 否 | 分割线与侧边栏底端的距离(不支持百分比设置)。 默认值:0.0 单位:vp 取值范围:[0, +∞)。 |
BarGridColumnOptions对象说明
支持设备PhonePC/2in1TabletWearable
TabBar栅格化方式设置的对象,包括栅格模式下的column边距和间隔,以及小、中、大屏下,页签占用的columns数量。
元服务API: 从API version 11开始,该接口支持在元服务中使用。
系统能力: SystemCapability.ArkUI.ArkUI.Full
名称 | 类型 | 必填 | 说明 |
---|---|---|---|
margin | Dimension | 否 | 栅格模式下的column边距(不支持百分比设置)。 默认值:24.0 单位:vp |
gutter | Dimension | 否 | 栅格模式下的column间隔(不支持百分比设置)。 默认值:24.0 单位:vp |
sm | number | 否 | 小屏下,页签占用的columns数量,必须是非负偶数。小屏为大于等于320vp但小于600vp。 默认值为-1,代表页签占用TabBar全部宽度。 |
md | number | 否 | 中屏下,页签占用的columns数量,必须是非负偶数。中屏为大于等于600vp但小于800vp。 默认值为-1,代表页签占用TabBar全部宽度。 |
lg | number | 否 | 大屏下,页签占用的columns数量,必须是非负偶数。大屏为大于等于840vp但小于1024vp。 默认值为-1,代表页签占用TabBar全部宽度。 |
ScrollableBarModeOptions对象说明
支持设备PhonePC/2in1TabletWearable
Scrollable模式下的TabBar的布局样式对象。
元服务API: 从API version 11开始,该接口支持在元服务中使用。
系统能力: SystemCapability.ArkUI.ArkUI.Full
名称 | 类型 | 必填 | 说明 |
---|---|---|---|
margin | Dimension | 否 | Scrollable模式下的TabBar的左右边距(不支持百分比设置)。 默认值:0.0 单位:vp 取值范围:[0, +∞)。 |
nonScrollableLayoutStyle | LayoutStyle | 否 | Scrollable模式下不滚动时的页签排布方式。 默认值:LayoutStyle.ALWAYS_CENTER |
BarMode枚举说明
支持设备PhonePC/2in1TabletWearable
TabBar布局模式枚举。
元服务API: 从API version 11开始,该接口支持在元服务中使用。
系统能力: SystemCapability.ArkUI.ArkUI.Full
名称 | 值 | 说明 |
---|---|---|
Scrollable | 0 | 每一个TabBar均使用实际布局宽度,超过总长度(横向Tabs的barWidth,纵向Tabs的barHeight)后可滑动。 |
Fixed | 1 | 所有TabBar平均分配barWidth宽度(纵向时平均分配barHeight高度)。 |
AnimationMode枚举说明
支持设备PhonePC/2in1TabletWearable
点击TabBar页签时切换TabContent的动画形式枚举。
系统能力: SystemCapability.ArkUI.ArkUI.Full
名称 | 值 | 说明 |
---|---|---|
CONTENT_FIRST | 0 | 先加载目标页内容,再开始切换动画。 元服务API: 从API version 12开始,该接口支持在元服务中使用。 |
ACTION_FIRST | 1 | 先开始切换动画,再加载目标页内容;生效需要同时需要满足:Tabs的height、width没有设置成auto。 元服务API: 从API version 12开始,该接口支持在元服务中使用。 |
NO_ANIMATION | 2 | 关闭默认动画。调用TabsController的changeIndex接口切换TabContent时该枚举值不生效。 可以通过设置animationDuration为0实现调用TabsController的changeIndex接口时不带动画。 元服务API: 从API version 12开始,该接口支持在元服务中使用。 |
CONTENT_FIRST_WITH_JUMP | 3 | 先加载目标页内容,再无动画跳转到目标页附近,最后有动画跳转到目标页。 元服务API: 从API version 15开始,该接口支持在元服务中使用。 |
ACTION_FIRST_WITH_JUMP | 4 | 先无动画跳转到目标页附近,再有动画跳转到目标页,最后加载目标页内容。此项生效需要同时需要满足:Tabs的height、width没有设置成auto。 元服务API: 从API version 15开始,该接口支持在元服务中使用。 |
LayoutStyle枚举说明
支持设备PhonePC/2in1TabletWearable
Scrollable模式下不滚动时的页签排布方式枚举。
元服务API: 从API version 11开始,该接口支持在元服务中使用。
系统能力: SystemCapability.ArkUI.ArkUI.Full
名称 | 值 | 说明 |
---|---|---|
ALWAYS_CENTER | 0 | 当页签内容超过TabBar宽度时,TabBar可滚动。 当页签内容不超过TabBar宽度时,TabBar不可滚动,页签紧凑居中。 |
ALWAYS_AVERAGE_SPLIT | 1 | 当页签内容超过TabBar宽度时,TabBar可滚动。 当页签内容不超过TabBar宽度时,TabBar不可滚动,且所有页签平均分配TabBar宽度。 |
SPACE_BETWEEN_OR_CENTER | 2 | 当页签内容超过TabBar宽度时,TabBar可滚动。 当页签内容不超过TabBar宽度但超过TabBar宽度一半时,TabBar不可滚动,页签紧凑居中。 当页签内容不超过TabBar宽度一半时,TabBar不可滚动,保证页签居中排列在TabBar宽度一半,且间距相同。 |
CommonModifier
支持设备PhonePC/2in1TabletWearable
type CommonModifier = CommonModifier
作为Tabs组件的参数对象。
元服务API: 从API version 15开始,该接口支持在元服务中使用。
系统能力: SystemCapability.ArkUI.ArkUI.Full
类型 | 说明 |
---|---|
CommonModifier | 设置TabBar的通用属性。 |
TabsCacheMode枚举说明
支持设备PhonePC/2in1TabletWearable
子组件的缓存模式。
元服务API: 从API version 19开始,该接口支持在元服务中使用。
系统能力: SystemCapability.ArkUI.ArkUI.Full
名称 | 值 | 说明 |
---|---|---|
CACHE_BOTH_SIDE | 0 | 缓存当前显示的子组件和其两侧的子组件。即当设置cachedMaxCount属性的count值为n时,最多缓存2n+1个子组件。 |
CACHE_LATEST_SWITCHED | 1 | 缓存当前显示的子组件和最近切换过的子组件。即当设置cachedMaxCount属性的count值为n时,最多缓存n+1个子组件。 |
事件
支持设备PhonePC/2in1TabletWearable
除支持通用事件外,还支持以下事件:
onChange
支持设备PhonePC/2in1TabletWearable
onChange(event: Callback<number>)
Tab页签切换后触发的事件。
满足以下任一条件,即可触发该事件:
1、滑动页面进行页面切换时,组件滑动动画结束后触发。
2、通过控制器调用changeIndex接口,Tab页签切换后触发。
3、动态修改状态变量构造的index属性值,Tab页签切换后触发。
4、点击TabBar页签,Tab页签切换后触发。
说明
使用自定义页签时,在onChange事件中联动可能会导致滑动页面切换后才执行页签联动,引起自定义页签切换效果延迟。建议在onAnimationStart中监听并刷新当前索引,以确保动效能够及时触发。具体实现可参考示例3。
元服务API: 从API version 11开始,该接口支持在元服务中使用。
系统能力: SystemCapability.ArkUI.ArkUI.Full
参数:
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
event | Callback<number> | 是 | 当前显示的index索引,索引从0开始计算。 |
onTabBarClick
支持设备PhonePC/2in1TabletWearable
onTabBarClick(event: Callback<number>)
Tab页签点击后触发的事件。
元服务API: 从API version 11开始,该接口支持在元服务中使用。
系统能力: SystemCapability.ArkUI.ArkUI.Full
参数:
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
event | Callback<number> | 是 | 被点击的index索引,索引从0开始计算。 |
onAnimationStart
支持设备PhonePC/2in1TabletWearable
onAnimationStart(handler: OnTabsAnimationStartCallback)
切换动画开始时触发该回调。当animationDuration为0时动画关闭,不触发该回调。
元服务API: 从API version 12开始,该接口支持在元服务中使用。
系统能力: SystemCapability.ArkUI.ArkUI.Full
参数:
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
handler | OnTabsAnimationStartCallback | 是 | 切换动画开始时触发的回调。 |
onAnimationEnd
支持设备PhonePC/2in1TabletWearable
onAnimationEnd(handler: OnTabsAnimationEndCallback)
切换动画结束时触发该回调,包括动画过程中手势中断。当animationDuration为0时动画关闭,不触发该回调。
元服务API: 从API version 12开始,该接口支持在元服务中使用。
系统能力: SystemCapability.ArkUI.ArkUI.Full
参数:
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
handler | OnTabsAnimationEndCallback | 是 | 切换动画结束时触发的回调。 |
onGestureSwipe
支持设备PhonePC/2in1TabletWearable
onGestureSwipe(handler: OnTabsGestureSwipeCallback)
在页面跟手滑动过程中,逐帧触发该回调。
元服务API: 从API version 12开始,该接口支持在元服务中使用。
系统能力: SystemCapability.ArkUI.ArkUI.Full
参数:
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
handler | OnTabsGestureSwipeCallback | 是 | 在页面跟手滑动过程中,逐帧触发的回调。 |
customContentTransition
支持设备PhonePC/2in1TabletWearable
customContentTransition(delegate: TabsCustomContentTransitionCallback)
自定义Tabs页面切换动画。
使用说明:
1、当使用自定义切换动画时,Tabs组件自带的默认切换动画会被禁用,同时,页面也无法跟手滑动。
2、当设置为undefined时,表示不使用自定义切换动画,仍然使用组件自带的默认切换动画。
3、当前自定义切换动画不支持打断。
4、目前自定义切换动画只支持两种场景触发:点击页签和调用TabsController.changeIndex()接口。
5、当使用自定义切换动画时,Tabs组件支持的事件中,除了onGestureSwipe,其他事件均支持。
6、onChange和onAnimationEnd事件的触发时机需要特殊说明:如果在第一次自定义动画执行过程中,触发了第二次自定义动画,那么在开始第二次自定义动画时,就会触发第一次自定义动画的onChange和onAnimationEnd事件。
7、当使用自定义动画时,参与动画的页面布局方式会改为Stack布局。如果开发者未主动设置相关页面的zIndex属性,那么所有页面的zIndex值是一样的,页面的渲染层级会按照在组件树上的顺序(即页面的index值顺序)确定。因此,开发者需要主动修改页面的zIndex属性,来控制页面的渲染层级。
元服务API: 从API version 12开始,该接口支持在元服务中使用。
系统能力: SystemCapability.ArkUI.ArkUI.Full
参数:
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
delegate | TabsCustomContentTransitionCallback | 是 | 自定义Tabs页面切换动画开始时触发的回调。 |
onContentWillChange
支持设备PhonePC/2in1TabletWearable
onContentWillChange(handler: OnTabsContentWillChangeCallback)
自定义Tabs页面切换拦截事件能力,新页面即将显示时触发该回调。
满足以下任一条件,即可触发该事件:
1、滑动TabContent切换新页面时触发。
2、通过TabsController.changeIndex接口切换新页面时触发。
3、通过动态修改index属性值切换新页面时触发。
4、通过点击TabBar页签切换新页面时触发。
5、TabBar页签获焦后,通过键盘左右方向键等切换新页面时触发。
元服务API: 从API version 12开始,该接口支持在元服务中使用。
系统能力: SystemCapability.ArkUI.ArkUI.Full
参数:
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
handler | OnTabsContentWillChangeCallback | 是 | 自定义Tabs页面切换拦截事件能力,新页面即将显示时触发的回调。 |
onSelected
支持设备PhonePC/2in1TabletWearable
onSelected(event: Callback<number>)
当选中元素改变时触发该回调,返回值为当前选中的元素的索引值。
满足以下任一条件,即可触发该事件:
-
滑动离手时满足翻页阈值,开始切换动画时触发。
-
通过TabsController控制器调用changeIndex接口,开始切换动画时触发。
-
动态修改状态变量构造的index属性值后触发。
-
通过页签处点击触发。
元服务API: 从API version 18开始,该接口支持在元服务中使用。
系统能力: SystemCapability.ArkUI.ArkUI.Full
参数:
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
event | Callback<number> | 是 | 当前选中元素的索引。 |
说明
onSelected回调中不可通过TabsOptions的index设置当前显示页的索引,不可调用TabsController.changeIndex()方法。
onUnselected
支持设备PhonePC/2in1TabletWearable
onUnselected(event: Callback<number>)
当选中元素改变时触发该回调,返回值为将要隐藏的元素的索引值。
满足以下任一条件,即可触发该事件:
-
滑动离手时满足翻页阈值,开始切换动画时触发。
-
通过TabsController控制器调用changeIndex接口,开始切换动画时触发。
-
动态修改状态变量构造的index属性值后触发。
-
通过页签处点击触发。
元服务API: 从API version 18开始,该接口支持在元服务中使用。
系统能力: SystemCapability.ArkUI.ArkUI.Full
参数:
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
event | Callback<number> | 是 | 将要隐藏元素的索引。 |
说明
onUnselected回调中不可通过TabsOptions的index设置当前显示页的索引,不可调用TabsController.changeIndex()方法。
OnTabsAnimationStartCallback
支持设备PhonePC/2in1TabletWearable
type OnTabsAnimationStartCallback = (index: number, targetIndex: number, extraInfo: TabsAnimationEvent) => void
切换动画开始时触发的回调。
元服务API: 从API version 18开始,该接口支持在元服务中使用。
系统能力: SystemCapability.ArkUI.ArkUI.Full
参数:
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
index | number | 是 | 当前显示元素的索引,索引从0开始。 |
targetIndex | number | 是 | 切换动画目标元素的索引,索引从0开始。 |
extraInfo | TabsAnimationEvent | 是 | 动画相关信息,包括主轴方向上当前显示元素和目标元素相对Tabs起始位置的位移,以及离手速度。 |
OnTabsAnimationEndCallback
支持设备PhonePC/2in1TabletWearable
type OnTabsAnimationEndCallback = (index: number, extraInfo: TabsAnimationEvent) => void
切换动画结束时触发的回调。
元服务API: 从API version 18开始,该接口支持在元服务中使用。
系统能力: SystemCapability.ArkUI.ArkUI.Full
参数:
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
index | number | 是 | 当前显示元素的索引,索引从0开始。 |
extraInfo | TabsAnimationEvent | 是 | 动画相关信息,只返回主轴方向上当前显示元素相对于Tabs起始位置的位移。 |
OnTabsGestureSwipeCallback
支持设备PhonePC/2in1TabletWearable
type OnTabsGestureSwipeCallback = (index: number, extraInfo: TabsAnimationEvent) => void
在页面跟手滑动过程中,逐帧触发的回调。
元服务API: 从API version 18开始,该接口支持在元服务中使用。
系统能力: SystemCapability.ArkUI.ArkUI.Full
参数:
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
index | number | 是 | 当前显示元素的索引,索引从0开始。 |
extraInfo | TabsAnimationEvent | 是 | 动画相关信息,只返回主轴方向上当前显示元素相对于Tabs起始位置的位移。 |
TabsCustomContentTransitionCallback
支持设备PhonePC/2in1TabletWearable
type TabsCustomContentTransitionCallback = (from: number, to: number) => TabContentAnimatedTransition | undefined
自定义Tabs页面切换动画开始时触发的回调。
元服务API: 从API version 18开始,该接口支持在元服务中使用。
系统能力: SystemCapability.ArkUI.ArkUI.Full
参数:
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
from | number | 是 | 动画开始时,当前页面的index值,索引从0开始。 |
to | number | 是 | 动画开始时,目标页面的index值,索引从0开始。 |
返回值:
类型 | 说明 |
---|---|
TabContentAnimatedTransition | undefined | 自定义切换动画相关信息。 |
OnTabsContentWillChangeCallback
支持设备PhonePC/2in1TabletWearable
type OnTabsContentWillChangeCallback = (currentIndex: number, comingIndex: number) => boolean
自定义Tabs页面切换拦截事件能力,新页面即将显示时触发的回调。
元服务API: 从API version 18开始,该接口支持在元服务中使用。
系统能力: SystemCapability.ArkUI.ArkUI.Full
参数:
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
currentIndex | number | 是 | 当前显示页面的index索引,索引从0开始计算。 |
comingIndex | number | 是 | 将要显示的新页面的index索引。 |
返回值:
类型 | 说明 |
---|---|
boolean | 当回调函数handler的返回值为true时,Tabs可以切换到新页面。 当回调函数handler的返回值为false时,Tabs无法切换到新页面,仍然显示原来页面内容。 |
TabsAnimationEvent对象说明
支持设备PhonePC/2in1TabletWearable
Tabs组件动画相关信息集合。
元服务API: 从API version 12开始,该接口支持在元服务中使用。
系统能力: SystemCapability.ArkUI.ArkUI.Full
名称 | 类型 | 只读 | 可选 | 说明 |
---|---|---|---|---|
currentOffset | number | 否 | 否 | Tabs当前显示元素在主轴方向上,相对于Tabs起始位置的位移。单位vp,默认值为0。 |
targetOffset | number | 否 | 否 | Tabs动画目标元素在主轴方向上,相对于Tabs起始位置的位移。单位vp,默认值为0。 |
velocity | number | 否 | 否 | Tabs离手动画开始时的离手速度。单位vp/s,默认值为0。 |
TabContentAnimatedTransition
支持设备PhonePC/2in1TabletWearable
Tabs自定义切换动画相关信息。
卡片能力: 从API version 11开始,该接口支持在ArkTS卡片中使用。
元服务API: 从API version 12开始,该接口支持在元服务中使用。
系统能力: SystemCapability.ArkUI.ArkUI.Full
名称 | 类型 | 必填 | 说明 |
---|---|---|---|
timeout | number | 否 | Tabs自定义切换动画超时时间。从自定义动画开始切换计时,如果到达该时间后,开发者仍未调用TabContentTransitionProxy的finishTransition接口通知Tabs组件自定义动画结束,那么组件就会认为此次自定义动画已结束,直接执行后续操作。 默认值:1000 单位:ms 取值范围:[0, +∞)。 |
transition | Callback<TabContentTransitionProxy> | 是 | 自定义切换动画具体内容。 |
TabContentTransitionProxy
支持设备PhonePC/2in1TabletWearable
Tabs自定义切换动画执行过程中,返回给开发者的proxy对象。开发者可通过该对象获取自定义动画的起始和目标页面信息,同时,也可以通过调用该对象的finishTransition接口通知Tabs组件自定义动画已结束。
卡片能力: 从API version 11开始,该接口支持在ArkTS卡片中使用。
元服务API: 从API version 12开始,该接口支持在元服务中使用。
系统能力: SystemCapability.ArkUI.ArkUI.Full
属性
名称 | 类型 | 只读 | 可选 | 说明 |
---|---|---|---|---|
from | number | 否 | 否 | 自定义动画起始页面对应的index值,索引从0开始。 |
to | number | 否 | 否 | 自定义动画目标页面对应的index值,索引从0开始。 |
finishTransition
支持设备PhonePC/2in1TabletWearable
finishTransition(): void
通知Tabs组件,此页面的自定义动画已结束。
卡片能力: 从API version 11开始,该接口支持在ArkTS卡片中使用。
元服务API: 从API version 12开始,该接口支持在元服务中使用。
系统能力: SystemCapability.ArkUI.ArkUI.Full
TabsController
支持设备PhonePC/2in1TabletWearable
Tabs组件的控制器,用于控制Tabs组件进行页签切换。不支持一个TabsController控制多个Tabs组件。
元服务API: 从API version 11开始,该接口支持在元服务中使用。
系统能力: SystemCapability.ArkUI.ArkUI.Full
constructor
支持设备PhonePC/2in1TabletWearable
constructor()
TabsController的构造函数。
元服务API: 从API version 11开始,该接口支持在元服务中使用。
系统能力: SystemCapability.ArkUI.ArkUI.Full
changeIndex
支持设备PhonePC/2in1TabletWearable
changeIndex(value: number): void
控制Tabs切换到指定页签。
元服务API: 从API version 11开始,该接口支持在元服务中使用。
系统能力: SystemCapability.ArkUI.ArkUI.Full
参数:
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
value | number | 是 | 页签在Tabs里的索引值,索引值从0开始。 说明: 设置小于0或大于最大数量的值时,取默认值0。 |
preloadItems
支持设备PhonePC/2in1TabletWearable
preloadItems(indices: Optional<Array<number>>): Promise<void>
控制Tabs预加载指定子节点。调用该接口后会一次性加载所有指定的子节点,因此为了性能考虑,建议分批加载子节点。
元服务API: 从API version 12开始,该接口支持在元服务中使用。
系统能力: SystemCapability.ArkUI.ArkUI.Full
参数:
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
indices | Optional<Array<number>> | 是 | 需预加载的子节点的下标数组。 默认值:空数组。 |
返回值:
类型 | 说明 |
---|---|
Promise<void> | 预加载完成后触发的回调。 |
错误码:
以下错误码的详细介绍请参见通用错误码。
错误码ID | 错误信息 |
---|---|
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. |
setTabBarTranslate
支持设备PhonePC/2in1TabletWearable
setTabBarTranslate(translate: TranslateOptions): void
设置TabBar的平移距离。
说明
当使用bindTabsToScrollable或bindTabsToNestedScrollable等接口绑定了Tabs组件和可滚动容器组件后,在滑动可滚动容器组件时,会触发所有与其绑定的Tabs组件的TabBar的显示和隐藏动效,调用setTabBarTranslate接口设置的TabBar平移距离会失效。因此不建议同时使用bindTabsToScrollable、bindTabsToNestedScrollable和setTabBarTranslate接口。
元服务API: 从API version 13开始,该接口支持在元服务中使用。
系统能力: SystemCapability.ArkUI.ArkUI.Full
参数:
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
translate | TranslateOptions | 是 | 设置TabBar的平移距离。 |
setTabBarOpacity
支持设备PhonePC/2in1TabletWearable
setTabBarOpacity(opacity: number): void
设置TabBar的不透明度。
说明
当使用bindTabsToScrollable或bindTabsToNestedScrollable等接口绑定了Tabs组件和可滚动容器组件后,在滑动可滚动容器组件时,会触发所有与其绑定的Tabs组件的TabBar的显示和隐藏动效,调用setTabBarOpacity接口设置的TabBar不透明度会失效。因此不建议同时使用bindTabsToScrollable、bindTabsToNestedScrollable和setTabBarOpacity接口。
元服务API: 从API version 13开始,该接口支持在元服务中使用。
系统能力: SystemCapability.ArkUI.ArkUI.Full
参数:
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
opacity | number | 是 | 设置TabBar的不透明度,取值范围为[0.0, 1.0]。 |
示例
支持设备PhonePC/2in1TabletWearable
示例1(设置TabBar的布局模式)
本示例通过barMode分别实现了页签均分布局和以实际长度布局,且展示了当页签布局长度之和超过了TabBar总长度后可滑动的效果。
- // xxx.ets
- @Entry
- @Component
- struct TabsExample {
- @State text: string = '文本';
- @State barMode: BarMode = BarMode.Fixed;
- build() {
- Column() {
- Row() {
- Button('文本增加 ')
- .width('47%')
- .height(50)
- .onClick((event?: ClickEvent) => {
- this.text += '文本增加';
- })
- .margin({ right: '6%', bottom: '12vp' })
- Button('文本重置')
- .width('47%')
- .height(50)
- .onClick((event?: ClickEvent) => {
- this.text = '文本';
- })
- .margin({ bottom: '12vp' })
- }
- Row() {
- Button('BarMode.Fixed')
- .width('47%')
- .height(50)
- .onClick((event?: ClickEvent) => {
- this.barMode = BarMode.Fixed;
- })
- .margin({ right: '6%', bottom: '12vp' })
- Button('BarMode.Scrollable')
- .width('47%')
- .height(50)
- .onClick((event?: ClickEvent) => {
- this.barMode = BarMode.Scrollable;
- })
- .margin({ bottom: '12vp' })
- }
- Tabs() {
- TabContent() {
- Column().width('100%').height('100%').backgroundColor(Color.Pink)
- }.tabBar(SubTabBarStyle.of(this.text))
- TabContent() {
- Column().width('100%').height('100%').backgroundColor(Color.Green)
- }.tabBar(SubTabBarStyle.of(this.text))
- TabContent() {
- Column().width('100%').height('100%').backgroundColor(Color.Blue)
- }.tabBar(SubTabBarStyle.of(this.text))
- }
- .height('60%')
- .backgroundColor(0xf1f3f5)
- .barMode(this.barMode)
- }
- .width('100%')
- .height(500)
- .padding('24vp')
- }
- }
示例2(设置Scrollable模式下的TabBar的布局样式)
本示例实现了barMode的ScrollableBarModeOptions参数,该参数仅在Scrollable模式下有效。
- // xxx.ets
- @Entry
- @Component
- struct TabsExample6 {
- private controller: TabsController = new TabsController();
- @State scrollMargin: number = 0;
- @State layoutStyle: LayoutStyle = LayoutStyle.ALWAYS_CENTER;
- @State text: string = '文本';
- build() {
- Column() {
- Row() {
- Button('scrollMargin+10 ' + this.scrollMargin)
- .width('47%')
- .height(50)
- .margin({ top: 5 })
- .onClick((event?: ClickEvent) => {
- this.scrollMargin += 10;
- })
- .margin({ right: '6%', bottom: '12vp' })
- Button('scrollMargin-10 ' + this.scrollMargin)
- .width('47%')
- .height(50)
- .margin({ top: 5 })
- .onClick((event?: ClickEvent) => {
- this.scrollMargin -= 10;
- })
- .margin({ bottom: '12vp' })
- }
- Row() {
- Button('文本增加 ')
- .width('47%')
- .height(50)
- .margin({ top: 5 })
- .onClick((event?: ClickEvent) => {
- this.text += '文本增加';
- })
- .margin({ right: '6%', bottom: '12vp' })
- Button('文本重置')
- .width('47%')
- .height(50)
- .margin({ top: 5 })
- .onClick((event?: ClickEvent) => {
- this.text = '文本';
- })
- .margin({ bottom: '12vp' })
- }
- Row() {
- Button('layoutStyle.ALWAYS_CENTER')
- .width('100%')
- .height(50)
- .margin({ top: 5 })
- .fontSize(15)
- .onClick((event?: ClickEvent) => {
- this.layoutStyle = LayoutStyle.ALWAYS_CENTER;
- })
- .margin({ bottom: '12vp' })
- }
- Row() {
- Button('layoutStyle.ALWAYS_AVERAGE_SPLIT')
- .width('100%')
- .height(50)
- .margin({ top: 5 })
- .fontSize(15)
- .onClick((event?: ClickEvent) => {
- this.layoutStyle = LayoutStyle.ALWAYS_AVERAGE_SPLIT;
- })
- .margin({ bottom: '12vp' })
- }
- Row() {
- Button('layoutStyle.SPACE_BETWEEN_OR_CENTER')
- .width('100%')
- .height(50)
- .margin({ top: 5 })
- .fontSize(15)
- .onClick((event?: ClickEvent) => {
- this.layoutStyle = LayoutStyle.SPACE_BETWEEN_OR_CENTER;
- })
- .margin({ bottom: '12vp' })
- }
- Tabs({ barPosition: BarPosition.End, controller: this.controller }) {
- TabContent() {
- Column().width('100%').height('100%').backgroundColor(Color.Pink)
- }.tabBar(SubTabBarStyle.of(this.text))
- TabContent() {
- Column().width('100%').height('100%').backgroundColor(Color.Green)
- }.tabBar(SubTabBarStyle.of(this.text))
- TabContent() {
- Column().width('100%').height('100%').backgroundColor(Color.Blue)
- }.tabBar(SubTabBarStyle.of(this.text))
- }
- .animationDuration(300)
- .height('60%')
- .backgroundColor(0xf1f3f5)
- .barMode(BarMode.Scrollable, { margin: this.scrollMargin, nonScrollableLayoutStyle: this.layoutStyle })
- }
- .width('100%')
- .height(500)
- .margin({ top: 5 })
- .padding('24vp')
- }
- }
示例3(自定义页签切换联动)
本示例通过onAnimationStart、onChange实现切换时自定义tabBar和TabContent的联动。
- // xxx.ets
- @Entry
- @Component
- struct TabsExample {
- @State fontColor: string = '#182431';
- @State selectedFontColor: string = '#007DFF';
- @State currentIndex: number = 0;
- @State selectedIndex: number = 0;
- private controller: TabsController = new TabsController();
- @Builder tabBuilder(index: number, name: string) {
- Column() {
- Text(name)
- .fontColor(this.selectedIndex === index ? this.selectedFontColor : this.fontColor)
- .fontSize(16)
- .fontWeight(this.selectedIndex === index ? 500 : 400)
- .lineHeight(22)
- .margin({ top: 17, bottom: 7 })
- Divider()
- .strokeWidth(2)
- .color('#007DFF')
- .opacity(this.selectedIndex === index ? 1 : 0)
- }.width('100%')
- }
- build() {
- Column() {
- Tabs({ barPosition: BarPosition.Start, index: this.currentIndex, controller: this.controller }) {
- TabContent() {
- Column().width('100%').height('100%').backgroundColor('#00CB87')
- }.tabBar(this.tabBuilder(0, 'green'))
- TabContent() {
- Column().width('100%').height('100%').backgroundColor('#007DFF')
- }.tabBar(this.tabBuilder(1, 'blue'))
- TabContent() {
- Column().width('100%').height('100%').backgroundColor('#FFBF00')
- }.tabBar(this.tabBuilder(2, 'yellow'))
- TabContent() {
- Column().width('100%').height('100%').backgroundColor('#E67C92')
- }.tabBar(this.tabBuilder(3, 'pink'))
- }
- .vertical(false)
- .barMode(BarMode.Fixed)
- .barWidth(360)
- .barHeight(56)
- .animationDuration(400)
- .onChange((index: number) => {
- // currentIndex控制TabContent显示页签
- this.currentIndex = index;
- this.selectedIndex = index;
- })
- .onAnimationStart((index: number, targetIndex: number, event: TabsAnimationEvent) => {
- if (index === targetIndex) {
- return;
- }
- // selectedIndex控制自定义TabBar内Image和Text颜色切换
- this.selectedIndex = targetIndex;
- })
- .width(360)
- .height(296)
- .margin({ top: 52 })
- .backgroundColor('#F1F3F5')
- }.width('100%')
- }
- }
示例4(分割线基本属性)
本示例通过divider实现了分割线各种属性的展示。
- // xxx.ets
- @Entry
- @Component
- struct TabsDivider1 {
- private controller1: TabsController = new TabsController();
- @State dividerColor: string = 'red';
- @State strokeWidth: number = 2;
- @State startMargin: number = 0;
- @State endMargin: number = 0;
- @State nullFlag: boolean = false;
- build() {
- Column() {
- Tabs({ controller: this.controller1 }) {
- TabContent() {
- Column().width('100%').height('100%').backgroundColor(Color.Pink)
- }.tabBar('pink')
- TabContent() {
- Column().width('100%').height('100%').backgroundColor(Color.Yellow)
- }.tabBar('yellow')
- TabContent() {
- Column().width('100%').height('100%').backgroundColor(Color.Blue)
- }.tabBar('blue')
- TabContent() {
- Column().width('100%').height('100%').backgroundColor(Color.Green)
- }.tabBar('green')
- TabContent() {
- Column().width('100%').height('100%').backgroundColor(Color.Red)
- }.tabBar('red')
- }
- .vertical(true)
- .scrollable(true)
- .barMode(BarMode.Fixed)
- .barWidth(70)
- .barHeight(200)
- .animationDuration(400)
- .onChange((index: number) => {
- console.info(index.toString());
- })
- .height('200vp')
- .margin({ bottom: '12vp' })
- .divider(this.nullFlag ? null : {
- strokeWidth: this.strokeWidth,
- color: this.dividerColor,
- startMargin: this.startMargin,
- endMargin: this.endMargin
- })
- Button('常规Divider').width('100%').margin({ bottom: '12vp' })
- .onClick(() => {
- this.nullFlag = false;
- this.strokeWidth = 2;
- this.dividerColor = 'red';
- this.startMargin = 0;
- this.endMargin = 0;
- })
- Button('空Divider').width('100%').margin({ bottom: '12vp' })
- .onClick(() => {
- this.nullFlag = true;
- })
- Button('颜色变为蓝色').width('100%').margin({ bottom: '12vp' })
- .onClick(() => {
- this.dividerColor = 'blue';
- })
- Button('宽度增加').width('100%').margin({ bottom: '12vp' })
- .onClick(() => {
- this.strokeWidth += 2;
- })
- Button('宽度减小').width('100%').margin({ bottom: '12vp' })
- .onClick(() => {
- if (this.strokeWidth > 2) {
- this.strokeWidth -= 2;
- }
- })
- Button('上边距增加').width('100%').margin({ bottom: '12vp' })
- .onClick(() => {
- this.startMargin += 2;
- })
- Button('上边距减少').width('100%').margin({ bottom: '12vp' })
- .onClick(() => {
- if (this.startMargin > 2) {
- this.startMargin -= 2;
- }
- })
- Button('下边距增加').width('100%').margin({ bottom: '12vp' })
- .onClick(() => {
- this.endMargin += 2;
- })
- Button('下边距减少').width('100%').margin({ bottom: '12vp' })
- .onClick(() => {
- if (this.endMargin > 2) {
- this.endMargin -= 2;
- }
- })
- }.padding({ top: '24vp', left: '24vp', right: '24vp' })
- }
- }
示例5(设置TabBar渐隐)
本示例通过fadingEdge实现了切换子页签渐隐和不渐隐。
- // xxx.ets
- @Entry
- @Component
- struct TabsOpaque {
- @State message: string = 'Hello World';
- private controller: TabsController = new TabsController();
- private controller1: TabsController = new TabsController();
- @State selfFadingFade: boolean = true;
- build() {
- Column() {
- Button('子页签设置渐隐').width('100%').margin({ bottom: '12vp' })
- .onClick((event?: ClickEvent) => {
- this.selfFadingFade = true;
- })
- Button('子页签设置不渐隐').width('100%').margin({ bottom: '12vp' })
- .onClick((event?: ClickEvent) => {
- this.selfFadingFade = false;
- })
- Tabs({ barPosition: BarPosition.End, controller: this.controller }) {
- TabContent() {
- Column().width('100%').height('100%').backgroundColor(Color.Pink)
- }.tabBar('pink')
- TabContent() {
- Column().width('100%').height('100%').backgroundColor(Color.Yellow)
- }.tabBar('yellow')
- TabContent() {
- Column().width('100%').height('100%').backgroundColor(Color.Blue)
- }.tabBar('blue')
- TabContent() {
- Column().width('100%').height('100%').backgroundColor(Color.Green)
- }.tabBar('green')
- TabContent() {
- Column().width('100%').height('100%').backgroundColor(Color.Green)
- }.tabBar('green')
- TabContent() {
- Column().width('100%').height('100%').backgroundColor(Color.Green)
- }.tabBar('green')
- TabContent() {
- Column().width('100%').height('100%').backgroundColor(Color.Green)
- }.tabBar('green')
- TabContent() {
- Column().width('100%').height('100%').backgroundColor(Color.Green)
- }.tabBar('green')
- }
- .vertical(false)
- .scrollable(true)
- .barMode(BarMode.Scrollable)
- .barHeight(80)
- .animationDuration(400)
- .onChange((index: number) => {
- console.info(index.toString());
- })
- .fadingEdge(this.selfFadingFade)
- .height('30%')
- .width('100%')
- Tabs({ barPosition: BarPosition.Start, controller: this.controller1 }) {
- TabContent() {
- Column().width('100%').height('100%').backgroundColor(Color.Pink)
- }.tabBar('pink')
- TabContent() {
- Column().width('100%').height('100%').backgroundColor(Color.Yellow)
- }.tabBar('yellow')
- TabContent() {
- Column().width('100%').height('100%').backgroundColor(Color.Blue)
- }.tabBar('blue')
- TabContent() {
- Column().width('100%').height('100%').backgroundColor(Color.Green)
- }.tabBar('green')
- TabContent() {
- Column().width('100%').height('100%').backgroundColor(Color.Green)
- }.tabBar('green')
- TabContent() {
- Column().width('100%').height('100%').backgroundColor(Color.Green)
- }.tabBar('green')
- }
- .vertical(true)
- .scrollable(true)
- .barMode(BarMode.Scrollable)
- .barHeight(200)
- .barWidth(80)
- .animationDuration(400)
- .onChange((index: number) => {
- console.info(index.toString());
- })
- .fadingEdge(this.selfFadingFade)
- .height('30%')
- .width('100%')
- }
- .padding({ top: '24vp', left: '24vp', right: '24vp' })
- }
- }
示例6(设置TabBar叠加在TabContent内容上)
本示例通过barOverlap实现了TabBar是否背后变模糊并叠加在TabContent之上。
- // xxx.ets
- @Entry
- @Component
- struct barHeightTest {
- @State arr: number[] = [0, 1, 2, 3];
- @State barOverlap: boolean = true;
- build() {
- Column() {
- Text(`barOverlap ${this.barOverlap}`).fontSize(16)
- Button('barOverlap变化').width('100%').margin({ bottom: '12vp' })
- .onClick((event?: ClickEvent) => {
- if (this.barOverlap) {
- this.barOverlap = false;
- } else {
- this.barOverlap = true;
- }
- })
- Tabs({ barPosition: BarPosition.End }) {
- TabContent() {
- Column() {
- List({ space: 10 }) {
- ForEach(this.arr, (item: number) => {
- ListItem() {
- Text('item' + item).width('80%').height(200).fontSize(16).textAlign(TextAlign.Center).backgroundColor('#fff8b81e')
- }
- }, (item: string) => item)
- }.width('100%').height('100%')
- .lanes(2).alignListItem(ListItemAlign.Center)
- }.width('100%').height('100%')
- .backgroundColor(Color.Pink)
- }
- .tabBar(new BottomTabBarStyle($r('sys.media.ohos_icon_mask_svg'), '测试0'))
- }
- .scrollable(false)
- .height('60%')
- .barOverlap(this.barOverlap)
- }
- .height(500)
- .padding({ top: '24vp', left: '24vp', right: '24vp' })
- }
- }
示例7(设置TabBar栅格化可见区域)
本示例通过barGridAlign实现了以栅格化方式设置TabBar的可见区域。
- // xxx.ets
- @Entry
- @Component
- struct TabsExample5 {
- private controller: TabsController = new TabsController();
- @State gridMargin: number = 10;
- @State gridGutter: number = 10;
- @State sm: number = -2;
- @State clickedContent: string = '';
- build() {
- Column() {
- Row() {
- Button('gridMargin+10 ' + this.gridMargin)
- .width('47%')
- .height(50)
- .margin({ top: 5 })
- .onClick((event?: ClickEvent) => {
- this.gridMargin += 10;
- })
- .margin({ right: '6%', bottom: '12vp' })
- Button('gridMargin-10 ' + this.gridMargin)
- .width('47%')
- .height(50)
- .margin({ top: 5 })
- .onClick((event?: ClickEvent) => {
- this.gridMargin -= 10;
- })
- .margin({ bottom: '12vp' })
- }
- Row() {
- Button('gridGutter+10 ' + this.gridGutter)
- .width('47%')
- .height(50)
- .margin({ top: 5 })
- .onClick((event?: ClickEvent) => {
- this.gridGutter += 10;
- })
- .margin({ right: '6%', bottom: '12vp' })
- Button('gridGutter-10 ' + this.gridGutter)
- .width('47%')
- .height(50)
- .margin({ top: 5 })
- .onClick((event?: ClickEvent) => {
- this.gridGutter -= 10;
- })
- .margin({ bottom: '12vp' })
- }
- Row() {
- Button('sm+2 ' + this.sm)
- .width('47%')
- .height(50)
- .margin({ top: 5 })
- .onClick((event?: ClickEvent) => {
- this.sm += 2;
- })
- .margin({ right: '6%' })
- Button('sm-2 ' + this.sm).width('47%').height(50).margin({ top: 5 })
- .onClick((event?: ClickEvent) => {
- this.sm -= 2;
- })
- }
- Text('点击内容:' + this.clickedContent).width('100%').height(200).margin({ top: 5 })
- Tabs({ barPosition: BarPosition.End, controller: this.controller }) {
- TabContent() {
- Column().width('100%').height('100%').backgroundColor(Color.Pink)
- }.tabBar(BottomTabBarStyle.of($r('sys.media.ohos_app_icon'), '1'))
- TabContent() {
- Column().width('100%').height('100%').backgroundColor(Color.Green)
- }.tabBar(BottomTabBarStyle.of($r('sys.media.ohos_app_icon'), '2'))
- TabContent() {
- Column().width('100%').height('100%').backgroundColor(Color.Blue)
- }.tabBar(BottomTabBarStyle.of($r('sys.media.ohos_app_icon'), '3'))
- }
- .width('350vp')
- .animationDuration(300)
- .height('60%')
- .barGridAlign({ sm: this.sm, margin: this.gridMargin, gutter: this.gridGutter })
- .backgroundColor(0xf1f3f5)
- .onTabBarClick((index: number) => {
- this.clickedContent += 'now index ' + index + ' is clicked\n';
- })
- }
- .width('100%')
- .height(500)
- .margin({ top: 5 })
- .padding('10vp')
- }
- }
示例8(自定义Tabs页面切换动画)
本示例通过customContentTransition实现了自定义Tabs页面的切换动画。
- // xxx.ets
- interface itemType {
- text: string,
- backgroundColor: Color
- }
- @Entry
- @Component
- struct TabsCustomAnimationExample {
- @State data: itemType[] = [
- {
- text: 'Red',
- backgroundColor: Color.Red
- },
- {
- text: 'Yellow',
- backgroundColor: Color.Yellow
- },
- {
- text: 'Blue',
- backgroundColor: Color.Blue
- }];
- @State opacityList: number[] = [];
- @State scaleList: number[] = [];
- private durationList: number[] = [];
- private timeoutList: number[] = [];
- private customContentTransition: (from: number, to: number) => TabContentAnimatedTransition = (from: number, to: number) => {
- let tabContentAnimatedTransition = {
- timeout: this.timeoutList[from],
- transition: (proxy: TabContentTransitionProxy) => {
- this.scaleList[from] = 1.0;
- this.scaleList[to] = 0.5;
- this.opacityList[from] = 1.0;
- this.opacityList[to] = 0.5;
- this.getUIContext()?.animateTo({
- duration: this.durationList[from],
- onFinish: () => {
- proxy.finishTransition();
- }
- }, () => {
- this.scaleList[from] = 0.5;
- this.scaleList[to] = 1.0;
- this.opacityList[from] = 0.5;
- this.opacityList[to] = 1.0;
- });
- }
- } as TabContentAnimatedTransition;
- return tabContentAnimatedTransition;
- };
- aboutToAppear(): void {
- let duration = 1000;
- let timeout = 1000;
- for (let i = 1; i <= this.data.length; i++) {
- this.opacityList.push(1.0);
- this.scaleList.push(1.0);
- this.durationList.push(duration * i);
- this.timeoutList.push(timeout * i);
- }
- }
- build() {
- Column() {
- Tabs() {
- ForEach(this.data, (item: itemType, index: number) => {
- TabContent() {}
- .tabBar(item.text)
- .backgroundColor(item.backgroundColor)
- // 自定义动画变化透明度、缩放页面等
- .opacity(this.opacityList[index])
- .scale({ x: this.scaleList[index], y: this.scaleList[index] })
- })
- }
- .backgroundColor(0xf1f3f5)
- .width('100%')
- .height(500)
- .customContentTransition(this.customContentTransition)
- }
- }
- }
示例9(页面切换拦截)
本示例通过onContentWillChange实现了自定义页面手势滑动切换拦截。
- //xxx.ets
- @Entry
- @Component
- struct TabsExample {
- @State selectedIndex: number = 2;
- @State currentIndex: number = 2;
- private controller: TabsController = new TabsController();
- @Builder tabBuilder(title: string,targetIndex: number) {
- Column(){
- Image(this.selectedIndex === targetIndex ? $r('app.media.star_fill') : $r('app.media.star'))
- .width(24)
- .height(24)
- .margin({ bottom: 4 })
- .objectFit(ImageFit.Contain)
- Text(title).fontColor(this.selectedIndex === targetIndex ? '#1698CE' : '#6B6B6B')
- }.width('100%')
- .height(50)
- .justifyContent(FlexAlign.Center)
- }
- build() {
- Column() {
- Tabs({ barPosition: BarPosition.End, index: this.currentIndex, controller: this.controller }) {
- TabContent() {
- Column(){
- Text('首页的内容')
- }.width('100%').height('100%').backgroundColor('#00CB87').justifyContent(FlexAlign.Center)
- }.tabBar(this.tabBuilder('首页',0))
- TabContent() {
- Column(){
- Text('发现的内容')
- }.width('100%').height('100%').backgroundColor('#007DFF').justifyContent(FlexAlign.Center)
- }.tabBar(this.tabBuilder('发现',1))
- TabContent() {
- Column(){
- Text('推荐的内容')
- }.width('100%').height('100%').backgroundColor('#FFBF00').justifyContent(FlexAlign.Center)
- }.tabBar(this.tabBuilder('推荐',2))
- TabContent() {
- Column(){
- Text('我的内容')
- }.width('100%').height('100%').backgroundColor('#E67C92').justifyContent(FlexAlign.Center)
- }.tabBar(this.tabBuilder('我的',3))
- }
- .vertical(false)
- .barMode(BarMode.Fixed)
- .barWidth(360)
- .barHeight(60)
- .animationDuration(0)
- .onChange((index: number) => {
- this.currentIndex = index;
- this.selectedIndex = index;
- })
- .width(360)
- .height(600)
- .backgroundColor('#F1F3F5')
- .scrollable(true)
- .onContentWillChange((currentIndex, comingIndex) => {
- if (comingIndex == 2) {
- return false;
- }
- return true;
- })
- Button('动态修改index').width('50%').margin({ top: 20 })
- .onClick(()=>{
- this.currentIndex = (this.currentIndex + 1) % 4;
- })
- Button('changeIndex').width('50%').margin({ top: 20 })
- .onClick(()=>{
- this.currentIndex = (this.currentIndex + 1) % 4;
- this.controller.changeIndex(this.currentIndex);
- })
- }.width('100%')
- }
- }
示例10(自定义TabBar切换动画)
本示例通过onChange、onAnimationStart、onAnimationEnd、onGestureSwipe等接口实现了自定义TabBar的切换动画。
- // EntryAbility.ets
- import { Configuration, UIAbility } from '@kit.AbilityKit';
- import { i18n } from '@kit.LocalizationKit';
- import { CommonUtil } from '../common/CommonUtil';
- export default class EntryAbility extends UIAbility {
- onConfigurationUpdate(newConfig: Configuration): void {
- // 监听系统配置变化
- if (newConfig.language) {
- CommonUtil.setIsRTL(i18n.isRTL(newConfig.language));
- }
- }
- }
- // CommonUtil.ets
- import { i18n, intl } from '@kit.LocalizationKit';
- export class CommonUtil {
- private static isRTL: boolean = i18n.isRTL((new intl.Locale()).language);
- public static setIsRTL(isRTL: boolean): void {
- CommonUtil.isRTL = isRTL;
- }
- public static getIsRTL(): boolean {
- return CommonUtil.isRTL;
- }
- }
- // xxx.ets
- import { LengthMetrics } from '@kit.ArkUI';
- import { CommonUtil } from '../common/CommonUtil';
- @Entry
- @Component
- struct TabsExample {
- @State colorArray: [string, string][] =
- [['green', '#00CB87'], ['blue', '#007DFF'], ['yellow', '#FFBF00'], ['pink', '#E67C92']];
- @State currentIndex: number = 0;
- @State animationDuration: number = 300;
- @State indicatorLeftMargin: number = 0;
- @State indicatorWidth: number = 0;
- private tabsWidth: number = 0;
- private textInfos: [number, number][] = [];
- private isStartAnimateTo: boolean = false;
- aboutToAppear():void {
- for (let i = 0; i < this.colorArray.length; i++) {
- this.textInfos.push([0, 0]);
- }
- }
- @Builder
- tabBuilder(index: number, name: string) {
- Column() {
- Text(name)
- .fontSize(16)
- .fontColor(this.currentIndex === index ? '#007DFF' : '#182431')
- .fontWeight(this.currentIndex === index ? 500 : 400)
- .id(index.toString())
- .onAreaChange((oldValue: Area, newValue: Area) => {
- this.textInfos[index] = [newValue.globalPosition.x as number, newValue.width as number];
- if (!this.isStartAnimateTo && this.currentIndex === index && this.tabsWidth > 0) {
- this.setIndicatorAttr(this.textInfos[this.currentIndex][0], this.textInfos[this.currentIndex][1]);
- }
- })
- }.width('100%')
- }
- build() {
- Stack({ alignContent: Alignment.TopStart }) {
- Tabs({ barPosition: BarPosition.Start }) {
- ForEach(this.colorArray, (item: [string, string], index:number) => {
- TabContent() {
- Column().width('100%').height('100%').backgroundColor(item[1])
- }.tabBar(this.tabBuilder(index, item[0]))
- })
- }
- .onAreaChange((oldValue: Area, newValue: Area)=> {
- this.tabsWidth = newValue.width as number;
- if (!this.isStartAnimateTo) {
- this.setIndicatorAttr(this.textInfos[this.currentIndex][0], this.textInfos[this.currentIndex][1]);
- }
- })
- .barWidth('100%')
- .barHeight(56)
- .width('100%')
- .height(296)
- .backgroundColor('#F1F3F5')
- .animationDuration(this.animationDuration)
- .onChange((index: number) => {
- this.currentIndex = index; // 监听索引index的变化,实现页签内容的切换。
- })
- .onAnimationStart((index: number, targetIndex: number, event: TabsAnimationEvent) => {
- // 切换动画开始时触发该回调。下划线跟着页面一起滑动,同时宽度渐变。
- this.currentIndex = targetIndex;
- this.startAnimateTo(this.animationDuration, this.textInfos[targetIndex][0], this.textInfos[targetIndex][1]);
- })
- .onAnimationEnd((index: number, event: TabsAnimationEvent) => {
- // 切换动画结束时触发该回调。下划线动画停止。
- let currentIndicatorInfo = this.getCurrentIndicatorInfo(index, event);
- this.startAnimateTo(0, currentIndicatorInfo.left, currentIndicatorInfo.width);
- })
- .onGestureSwipe((index: number, event: TabsAnimationEvent) => {
- // 在页面跟手滑动过程中,逐帧触发该回调。
- let currentIndicatorInfo = this.getCurrentIndicatorInfo(index, event);
- this.currentIndex = currentIndicatorInfo.index;
- this.setIndicatorAttr(currentIndicatorInfo.left, currentIndicatorInfo.width);
- })
- Column()
- .height(2)
- .width(this.indicatorWidth)
- .margin({ start: LengthMetrics.vp(this.indicatorLeftMargin), top: LengthMetrics.vp(48) })
- .backgroundColor('#007DFF')
- }.width('100%')
- }
- private getCurrentIndicatorInfo(index: number, event: TabsAnimationEvent): Record<string, number> {
- let nextIndex = index;
- if (index > 0 && (CommonUtil.getIsRTL() ? event.currentOffset < 0 : event.currentOffset > 0)) {
- nextIndex--;
- } else if (index < this.textInfos.length - 1 &&
- (CommonUtil.getIsRTL() ? event.currentOffset > 0 : event.currentOffset < 0)) {
- nextIndex++;
- }
- let indexInfo = this.textInfos[index];
- let nextIndexInfo = this.textInfos[nextIndex];
- let swipeRatio = Math.abs(event.currentOffset / this.tabsWidth);
- let currentIndex = swipeRatio > 0.5 ? nextIndex : index; // 页面滑动超过一半,tabBar切换到下一页。
- let currentLeft = indexInfo[0] + (nextIndexInfo[0] - indexInfo[0]) * swipeRatio;
- let currentWidth = indexInfo[1] + (nextIndexInfo[1] - indexInfo[1]) * swipeRatio;
- return { 'index': currentIndex, 'left': currentLeft, 'width': currentWidth };
- }
- private startAnimateTo(duration: number, leftMargin: number, width: number) {
- this.isStartAnimateTo = true;
- this.getUIContext()?.animateTo({
- duration: duration, // 动画时长
- curve: Curve.Linear, // 动画曲线
- iterations: 1, // 播放次数
- playMode: PlayMode.Normal, // 动画模式
- onFinish: () => {
- this.isStartAnimateTo = false;
- console.info('play end');
- }
- }, () => {
- this.setIndicatorAttr(leftMargin, width);
- });
- }
- private setIndicatorAttr(leftMargin: number, width: number) {
- this.indicatorWidth = width;
- if (CommonUtil.getIsRTL()) {
- this.indicatorLeftMargin = this.tabsWidth - leftMargin - width;
- } else {
- this.indicatorLeftMargin = leftMargin;
- }
- }
- }
示例11(预加载子节点)
本示例通过preloadItems接口实现了预加载指定子节点。
- // xxx.ets
- import { BusinessError } from '@kit.BasicServicesKit';
- @Entry
- @Component
- struct TabsPreloadItems {
- @State currentIndex: number = 1;
- private tabsController: TabsController = new TabsController();
- build() {
- Column() {
- Tabs({ index: this.currentIndex, controller: this.tabsController }) {
- TabContent() {
- MyComponent({ color: '#00CB87' })
- }.tabBar(SubTabBarStyle.of('green'))
- TabContent() {
- MyComponent({ color: '#007DFF' })
- }.tabBar(SubTabBarStyle.of('blue'))
- TabContent() {
- MyComponent({ color: '#FFBF00' })
- }.tabBar(SubTabBarStyle.of('yellow'))
- TabContent() {
- MyComponent({ color: '#E67C92' })
- }.tabBar(SubTabBarStyle.of('pink'))
- }
- .width(360)
- .height(296)
- .backgroundColor('#F1F3F5')
- .onChange((index: number) => {
- this.currentIndex = index;
- })
- Button('preload items: [0, 2, 3]')
- .margin(5)
- .onClick(() => {
- // 预加载第0、2、3个子节点,提高滑动或点击切换至这些节点时的性能
- this.tabsController.preloadItems([0, 2, 3])
- .then(() => {
- console.info('preloadItems success.');
- })
- .catch((error: BusinessError) => {
- console.error('preloadItems failed, error code: ' + error.code + ', error message: ' + error.message);
- })
- })
- }
- }
- }
- @Component
- struct MyComponent {
- private color: string = '';
- aboutToAppear(): void {
- console.info('aboutToAppear backgroundColor:' + this.color);
- }
- aboutToDisappear(): void {
- console.info('aboutToDisappear backgroundColor:' + this.color);
- }
- build() {
- Column()
- .width('100%')
- .height('100%')
- .backgroundColor(this.color)
- }
- }
示例12(设置TabBar平移距离和不透明度)
本示例通过setTabBarTranslate、setTabBarOpacity等接口设置了TabBar的平移距离和不透明度。
- // xxx.ets
- @Entry
- @Component
- struct TabsExample {
- private controller: TabsController = new TabsController();
- build() {
- Column() {
- Button('设置TabBar的平移距离').margin({ top: 20 })
- .onClick(() => {
- this.controller.setTabBarTranslate({ x: -20, y: -20 });
- })
- Button('设置TabBar的透明度').margin({ top: 20 })
- .onClick(() => {
- this.controller.setTabBarOpacity(0.5);
- })
- Tabs({ barPosition: BarPosition.End, controller: this.controller }) {
- TabContent() {
- Column().width('100%').height('100%').backgroundColor('#00CB87')
- }.tabBar(BottomTabBarStyle.of($r('app.media.startIcon'), 'green'))
- TabContent() {
- Column().width('100%').height('100%').backgroundColor('#007DFF')
- }.tabBar(BottomTabBarStyle.of($r('app.media.startIcon'), 'blue'))
- TabContent() {
- Column().width('100%').height('100%').backgroundColor('#FFBF00')
- }.tabBar(BottomTabBarStyle.of($r('app.media.startIcon'), 'yellow'))
- TabContent() {
- Column().width('100%').height('100%').backgroundColor('#E67C92')
- }.tabBar(BottomTabBarStyle.of($r('app.media.startIcon'), 'pink'))
- }
- .width(360)
- .height(296)
- .margin({ top: 20 })
- .barBackgroundColor('#F1F3F5')
- }
- .width('100%')
- }
- }
示例13(页面懒加载和释放)
本示例通过使用自定义TabBar与Swiper配合LazyForEach实现页面懒加载和释放。
- // xxx.ets
- class MyDataSource implements IDataSource {
- private list: number[] = [];
- constructor(list: number[]) {
- this.list = list;
- }
- totalCount(): number {
- return this.list.length;
- }
- getData(index: number): number {
- return this.list[index];
- }
- registerDataChangeListener(listener: DataChangeListener): void {
- }
- unregisterDataChangeListener() {
- }
- }
- @Entry
- @Component
- struct TabsSwiperExample {
- @State fontColor: string = '#182431';
- @State selectedFontColor: string = '#007DFF';
- @State currentIndex: number = 0;
- private list: number[] = [];
- private tabsController: TabsController = new TabsController();
- private swiperController: SwiperController = new SwiperController();
- private swiperData: MyDataSource = new MyDataSource([]);
- aboutToAppear(): void {
- for (let i = 0; i <= 9; i++) {
- this.list.push(i);
- }
- this.swiperData = new MyDataSource(this.list);
- }
- @Builder tabBuilder(index: number, name: string) {
- Column() {
- Text(name)
- .fontColor(this.currentIndex === index ? this.selectedFontColor : this.fontColor)
- .fontSize(16)
- .fontWeight(this.currentIndex === index ? 500 : 400)
- .lineHeight(22)
- .margin({ top: 17, bottom: 7 })
- Divider()
- .strokeWidth(2)
- .color('#007DFF')
- .opacity(this.currentIndex === index ? 1 : 0)
- }.width('20%')
- }
- build() {
- Column() {
- Tabs({ barPosition: BarPosition.Start, controller: this.tabsController }) {
- ForEach(this.list, (item: number) => {
- TabContent().tabBar(this.tabBuilder(item, '页签 ' + this.list[item]))
- })
- }
- .onTabBarClick((index: number) => {
- this.currentIndex = index;
- this.swiperController.changeIndex(index, true);
- })
- .barMode(BarMode.Scrollable)
- .backgroundColor('#F1F3F5')
- .height(56)
- .width('100%')
- Swiper(this.swiperController) {
- LazyForEach(this.swiperData, (item: string) => {
- Text(item.toString())
- .onAppear(()=>{
- console.info('onAppear ' + item.toString());
- })
- .onDisAppear(()=>{
- console.info('onDisAppear ' + item.toString());
- })
- .width('100%')
- .height('100%')
- .backgroundColor(0xAFEEEE)
- .textAlign(TextAlign.Center)
- .fontSize(30)
- }, (item: string) => item)
- }
- .loop(false)
- .onChange((index: number) => {
- this.currentIndex = index;
- })
- .onAnimationStart((index: number, targetIndex: number, extraInfo: SwiperAnimationEvent) => {
- this.currentIndex = targetIndex;
- this.tabsController.changeIndex(targetIndex);
- })
- }
- }
- }
示例14(设置翻页动效)
本示例通过设置animationMode属性,实现了翻页的动效。
- // xxx.ets
- @Entry
- @Component
- struct TabsExample {
- @State currentIndex: number = 0;
- @State currentAnimationMode: AnimationMode = AnimationMode.CONTENT_FIRST;
- private controller: TabsController = new TabsController();
- private data: number[] = [];
- aboutToAppear(): void {
- for (let i = 0; i < 10; i++) {
- this.data.push(i);
- }
- }
- @Builder
- tabBuilder(title: string,targetIndex: number) {
- Column(){
- Text(title).fontColor(this.currentIndex === targetIndex ? '#FF0000' : '#6B6B6B')
- }.width('100%')
- .height(50)
- .justifyContent(FlexAlign.Center)
- }
- build() {
- Column() {
- Tabs({ barPosition: BarPosition.End, controller: this.controller, index: this.currentIndex }) {
- ForEach(this.data, (item: string) => {
- TabContent() {
- Column(){
- Text('' + item)
- }.width('100%').height('100%').backgroundColor('#00CB87').justifyContent(FlexAlign.Center)
- }.tabBar(this.tabBuilder('P' + item, parseInt(item)))
- }, (item: string) => item)
- }
- .barWidth(360)
- .barHeight(60)
- .animationMode(this.currentAnimationMode)
- .animationDuration(4000)
- .onChange((index: number) => {
- this.currentIndex = index;
- })
- .width(360)
- .height(120)
- .backgroundColor('#F1F3F5')
- Text('AnimationMode:' + AnimationMode[this.currentAnimationMode])
- Button('AnimationMode').width('50%').margin({ top: 1 }).height(25)
- .onClick(()=>{
- if (this.currentAnimationMode === AnimationMode.CONTENT_FIRST) {
- this.currentAnimationMode = AnimationMode.ACTION_FIRST;
- } else if (this.currentAnimationMode === AnimationMode.ACTION_FIRST) {
- this.currentAnimationMode = AnimationMode.NO_ANIMATION;
- } else if (this.currentAnimationMode === AnimationMode.NO_ANIMATION) {
- this.currentAnimationMode = AnimationMode.CONTENT_FIRST_WITH_JUMP;
- } else if (this.currentAnimationMode === AnimationMode.CONTENT_FIRST_WITH_JUMP) {
- this.currentAnimationMode = AnimationMode.ACTION_FIRST_WITH_JUMP;
- } else if (this.currentAnimationMode === AnimationMode.ACTION_FIRST_WITH_JUMP) {
- this.currentAnimationMode = AnimationMode.CONTENT_FIRST;
- }
- })
- }.width('100%')
- }
- }
示例15(页签超出TabBar区域显示)
本示例通过使用barModifier设置tabBar的clip属性实现页签超出tabBar区域显示效果。
- // xxx.ets
- import { CommonModifier } from '@kit.ArkUI';
- @Entry
- @Component
- struct TabsBarModifierExample {
- @State selectedIndex: number = 2;
- @State currentIndex: number = 2;
- @State isClip: boolean = false;
- @State tabBarModifier: CommonModifier = new CommonModifier();
- private controller: TabsController = new TabsController();
- aboutToAppear(): void {
- this.tabBarModifier.clip(this.isClip);
- }
- @Builder
- tabBuilder(title: string, targetIndex: number) {
- Column() {
- Image($r('app.media.startIcon')).width(30).height(30)
- Text(title).fontColor(this.selectedIndex === targetIndex ? '#1698CE' : '#6B6B6B')
- }.width('100%')
- .height(50)
- .justifyContent(FlexAlign.Center)
- .offset({ y: this.selectedIndex === targetIndex ? -15 : 0 })
- }
- build() {
- Column() {
- Tabs({
- barPosition: BarPosition.End,
- index: this.currentIndex,
- controller: this.controller,
- barModifier: this.tabBarModifier
- }) {
- TabContent() {
- Column() {
- Text('首页的内容')
- }.width('100%').height('100%').backgroundColor('#00CB87').justifyContent(FlexAlign.Center)
- }.tabBar(this.tabBuilder('首页', 0))
- TabContent() {
- Column() {
- Text('发现的内容')
- }.width('100%').height('100%').backgroundColor('#007DFF').justifyContent(FlexAlign.Center)
- }.tabBar(this.tabBuilder('发现', 1))
- TabContent() {
- Column() {
- Text('推荐的内容')
- }.width('100%').height('100%').backgroundColor('#FFBF00').justifyContent(FlexAlign.Center)
- }.tabBar(this.tabBuilder('推荐', 2))
- TabContent() {
- Column() {
- Text('我的内容')
- }.width('100%').height('100%').backgroundColor('#E67C92').justifyContent(FlexAlign.Center)
- }.tabBar(this.tabBuilder('我的', 3))
- }
- .vertical(false)
- .barMode(BarMode.Fixed)
- .barWidth(340)
- .barHeight(60)
- .onChange((index: number) => {
- this.currentIndex = index;
- this.selectedIndex = index;
- })
- .width(340)
- .height(400)
- .backgroundColor('#F1F3F5')
- .scrollable(true)
- Button('isClip: ' + this.isClip)
- .margin({ top: 30 })
- .onClick(() => {
- this.isClip = !this.isClip;
- this.tabBarModifier.clip(this.isClip);
- })
- }.width('100%')
- }
- }
示例16(页签对齐布局)
本示例通过使用barModifier设置tabBar的align属性实现页签对齐布局效果。
- // xxx.ets
- import { CommonModifier } from '@kit.ArkUI';
- @Entry
- @Component
- struct TabsBarModifierExample {
- private controller: TabsController = new TabsController();
- @State text: string = '文本';
- @State isVertical: boolean = false;
- @State tabBarModifier: CommonModifier = new CommonModifier();
- build() {
- Column() {
- Row() {
- Button('Alignment.Start ')
- .width('47%')
- .height(50)
- .margin({ top: 5 })
- .onClick((event?: ClickEvent) => {
- this.tabBarModifier.align(Alignment.Start);
- })
- .margin({ right: '6%', bottom: '12vp' })
- Button('Alignment.End')
- .width('47%')
- .height(50)
- .margin({ top: 5 })
- .onClick((event?: ClickEvent) => {
- this.tabBarModifier.align(Alignment.End);
- })
- .margin({ bottom: '12vp' })
- }
- Row() {
- Button('Alignment.Center')
- .width('47%')
- .height(50)
- .margin({ top: 5 })
- .onClick((event?: ClickEvent) => {
- this.tabBarModifier.align(Alignment.Center);
- })
- .margin({ right: '6%', bottom: '12vp' })
- Button('isVertical: ' + this.isVertical)
- .width('47%')
- .height(50)
- .margin({ top: 5 })
- .onClick((event?: ClickEvent) => {
- this.isVertical = !this.isVertical;
- })
- .margin({ bottom: '12vp' })
- }
- Row() {
- Button('Alignment.Top')
- .width('47%')
- .height(50)
- .margin({ top: 5 })
- .onClick((event?: ClickEvent) => {
- this.tabBarModifier.align(Alignment.Top);
- })
- .margin({ right: '6%', bottom: '12vp' })
- Button('Alignment.Bottom')
- .width('47%')
- .height(50)
- .margin({ top: 5 })
- .onClick((event?: ClickEvent) => {
- this.tabBarModifier.align(Alignment.Bottom);
- })
- .margin({ bottom: '12vp' })
- }
- Tabs({ barPosition: BarPosition.End, controller: this.controller, barModifier: this.tabBarModifier }) {
- TabContent() {
- Column().width('100%').height('100%').backgroundColor(Color.Pink)
- }.tabBar(SubTabBarStyle.of(this.text))
- TabContent() {
- Column().width('100%').height('100%').backgroundColor(Color.Green)
- }.tabBar(SubTabBarStyle.of(this.text))
- TabContent() {
- Column().width('100%').height('100%').backgroundColor(Color.Blue)
- }.tabBar(SubTabBarStyle.of(this.text))
- }
- .vertical(this.isVertical)
- .height('60%')
- .backgroundColor(0xf1f3f5)
- .barMode(BarMode.Scrollable)
- }
- .width('100%')
- .height(500)
- .margin({ top: 5 })
- .padding('24vp')
- }
- }
示例17(Tabs与TabBar联动切换)
该示例通过onSelected接口,实现了Tabs与TabBar联动切换。
- // xxx.ets
- @Entry
- @Component
- struct TabsExample {
- @State fontColor: string = '#182431';
- @State selectedFontColor: string = '#007DFF';
- @State currentIndex: number = 0;
- @State selectedIndex: number = 0;
- private controller: TabsController = new TabsController();
- @Builder tabBuilder(index: number, name: string) {
- Column() {
- Text(name)
- .fontColor(this.selectedIndex === index ? this.selectedFontColor : this.fontColor)
- .fontSize(16)
- .fontWeight(this.selectedIndex === index ? 500 : 400)
- .lineHeight(22)
- .margin({ top: 17, bottom: 7 })
- Divider()
- .strokeWidth(2)
- .color('#007DFF')
- .opacity(this.selectedIndex === index ? 1 : 0)
- }.width('100%')
- }
- build() {
- Column() {
- Tabs({ barPosition: BarPosition.Start, index: this.currentIndex, controller: this.controller }) {
- TabContent() {
- Column().width('100%').height('100%').backgroundColor('#00CB87')
- }.tabBar(this.tabBuilder(0, 'green'))
- TabContent() {
- Column().width('100%').height('100%').backgroundColor('#007DFF')
- }.tabBar(this.tabBuilder(1, 'blue'))
- TabContent() {
- Column().width('100%').height('100%').backgroundColor('#FFBF00')
- }.tabBar(this.tabBuilder(2, 'yellow'))
- TabContent() {
- Column().width('100%').height('100%').backgroundColor('#E67C92')
- }.tabBar(this.tabBuilder(3, 'pink'))
- }
- .vertical(false)
- .barMode(BarMode.Fixed)
- .barWidth(360)
- .barHeight(56)
- .animationDuration(400)
- .animationMode(AnimationMode.CONTENT_FIRST)
- .onChange((index: number) => {
- console.log('onChange index:' + index);
- this.currentIndex = index;
- })
- .onSelected((index: number) => {
- console.log('onSelected index:' + index);
- this.selectedIndex = index;
- })
- .onUnselected((index: number) => {
- console.log('onUnselected index:' + index);
- })
- .width('100%')
- .height('100%')
- .backgroundColor('#F1F3F5')
- }.width('100%')
- }
- }
示例18(释放Tabs子组件)
该示例通过设置cachedMaxCount属性,实现了Tabs子组件的释放。
- @Entry
- @Component
- struct TabsExample {
- build() {
- Tabs() {
- TabContent() {
- MyComponent({ color: '#00CB87' })
- }.tabBar(SubTabBarStyle.of('green'))
- TabContent() {
- MyComponent({ color: '#007DFF' })
- }.tabBar(SubTabBarStyle.of('blue'))
- TabContent() {
- MyComponent({ color: '#FFBF00' })
- }.tabBar(SubTabBarStyle.of('yellow'))
- TabContent() {
- MyComponent({ color: '#E67C92' })
- }.tabBar(SubTabBarStyle.of('pink'))
- }
- .width(360)
- .height(296)
- .backgroundColor('#F1F3F5')
- .cachedMaxCount(1, TabsCacheMode.CACHE_BOTH_SIDE)
- }
- }
- @Component
- struct MyComponent {
- private color: string = '';
- aboutToAppear(): void {
- console.info('aboutToAppear backgroundColor:' + this.color);
- }
- aboutToDisappear(): void {
- console.info('aboutToDisappear backgroundColor:' + this.color);
- }
- build() {
- Column()
- .width('100%')
- .height('100%')
- .backgroundColor(this.color)
- }
- }
示例19(设置TabBar背景模糊效果)
该示例分别通过barBackgroundBlurStyle和barBackgroundEffect设置TabsBar页签栏的背景模糊效果。
- // xxx.ets
- @Entry
- @Component
- struct TabsExample {
- build() {
- Column() {
- // barBackgroundBlurStyle 可以通过枚举值的方式设置模糊参数
- Stack() {
- Image($r('app.media.startIcon'))
- Tabs() {
- TabContent() {
- Column().width('100%').height('100%').backgroundColor('#00CB87')
- }.tabBar('green')
- TabContent() {
- Column().width('100%').height('100%').backgroundColor('#007DFF')
- }.tabBar('blue')
- TabContent() {
- Column().width('100%').height('100%').backgroundColor('#FFBF00')
- }.tabBar('yellow')
- TabContent() {
- Column().width('100%').height('100%').backgroundColor('#E67C92')
- }.tabBar('pink')
- }
- .barBackgroundBlurStyle(BlurStyle.COMPONENT_THICK,
- { colorMode: ThemeColorMode.LIGHT, adaptiveColor: AdaptiveColor.DEFAULT, scale: 1.0 })
- }
- .width(300)
- .height(300)
- .margin(10)
- // barBackgroundEffect 可以自定义设置tabBar页签栏的模糊半径、亮度、饱和度等参数
- Stack() {
- Image($r('app.media.startIcon'))
- Tabs() {
- TabContent() {
- Column().width('100%').height('100%').backgroundColor('#00CB87')
- }.tabBar('green')
- TabContent() {
- Column().width('100%').height('100%').backgroundColor('#007DFF')
- }.tabBar('blue')
- TabContent() {
- Column().width('100%').height('100%').backgroundColor('#FFBF00')
- }.tabBar('yellow')
- TabContent() {
- Column().width('100%').height('100%').backgroundColor('#E67C92')
- }.tabBar('pink')
- }
- .barBackgroundEffect({ radius: 20, brightness: 0.6, saturation: 15 })
- }
- .width(300)
- .height(300)
- .margin(10)
- }
- }
- }
示例20(设置边缘滑动效果)
该示例通过edgeEffect实现不同边缘滑动效果。
- // xxx.ets
- @Entry
- @Component
- struct TabsExample {
- @State edgeEffect: EdgeEffect = EdgeEffect.Spring;
- build() {
- Column() {
- Tabs() {
- TabContent() {
- Column().width('100%').height('100%').backgroundColor('#00CB87')
- }.tabBar('green')
- TabContent() {
- Column().width('100%').height('100%').backgroundColor('#007DFF')
- }.tabBar('blue')
- TabContent() {
- Column().width('100%').height('100%').backgroundColor('#FFBF00')
- }.tabBar('yellow')
- TabContent() {
- Column().width('100%').height('100%').backgroundColor('#E67C92')
- }.tabBar('pink')
- }
- .width(360)
- .height(296)
- .margin({ top: 52 })
- .backgroundColor('#F1F3F5')
- .edgeEffect(this.edgeEffect)
- Button('EdgeEffect.Spring').width('50%').margin({ top: 20 })
- .onClick(() => {
- this.edgeEffect = EdgeEffect.Spring;
- })
- Button('EdgeEffect.Fade').width('50%').margin({ top: 20 })
- .onClick(() => {
- this.edgeEffect = EdgeEffect.Fade;
- })
- Button('EdgeEffect.None').width('50%').margin({ top: 20 })
- .onClick(() => {
- this.edgeEffect = EdgeEffect.None;
- })
- }.width('100%')
- }
- }
示例21(Tabs设置翻页动画曲线)
该示例展示了如何通过animationCurve接口设置Tabs翻页动画曲线,并结合animationDuration设置翻页动画的时长。
- import { curves } from '@kit.ArkUI';
- interface TabsItemType { text: string, backgroundColor: ResourceColor }
- @Entry
- @Component
- struct TabsExample {
- private tabsController: TabsController = new TabsController();
- private curves: (Curve | ICurve) [] = [
- curves.interpolatingSpring(-1, 1, 328, 34),
- curves.springCurve(10, 1, 228, 30),
- curves.cubicBezierCurve(0.25, 0.1, 0.25, 1.0),
- ];
- @State curveIndex: number = 0;
- private datas: TabsItemType[] = [
- { text: '1', backgroundColor: '#004AAF' },
- { text: '2', backgroundColor: '#2787D9' },
- { text: '3', backgroundColor: '#D5D5D5' },
- { text: '4', backgroundColor: '#707070' },
- { text: '5', backgroundColor: '#F7F7F7' },
- ];
- @State duration: number = 0;
- build() {
- Column({ space:2 }) {
- Tabs({ controller: this.tabsController }) {
- ForEach(this.datas, (item: TabsItemType, index: number) => {
- TabContent() {}
- .tabBar(item.text)
- .backgroundColor(item.backgroundColor)
- })
- }
- .backgroundColor(0xf1f3f5)
- .width('100%')
- .height(500)
- .animationCurve(this.curves[this.curveIndex])
- .animationDuration(this.duration)
- Row({ space:2 }) {
- Text('Curve:' + this.curveIndex)
- Button('++').onClick(() => { this.curveIndex = (this.curveIndex + 1) % this.curves.length; })
- Button('reset').onClick(() => { this.curveIndex = 0; })
- }
- .margin({ left: '10vp' })
- .width('100%')
- Row({ space:2 }) {
- Text('Duration:' + this.duration)
- Button('+100').onClick(() => { this.duration = (this.duration + 100) % 10000; })
- Button('+1000').onClick(() => { this.duration = (this.duration + 1000) % 10000; })
- Button('reset').onClick(() => { this.duration = 0; })
- }
- .margin({ left: '10vp' })
- .width('100%')
- }
- .margin('10vp')
- }
- }
相关文章:
鸿蒙ArkUI---基础组件Tabs(Tabbar)
基础页面组件 Tabs 作用: 快速创建Tabbar 个人理解: 快速的创建Tabar。 效果图: 代码:interface TabItem {icon: Resource; //未选中activeIcon: Resource; //选中name: string; //文字 }Entry Component struct Index {// st…...
50. Pow(x, n)快速幂算法
实现 pow(x, n) ,即计算 x 的整数 n 次幂函数(即,xn )。此函数应将 x 作为浮点数(意味着它可以是十进制数)和 n 作为整数(可以是正数、负数或零)一起使用。 快速幂(Expo…...
Python函数
三.函数进阶 0.定义 函数三要素:函数名,参数,返回值,其中只有函数名是必须要的,参数,返回值可以没有 语法: def 函数名(参数): 函数体 return 返回值 1.…...
7.Spring框架
# spring框架Spring3.0开启了纯注解开发模式,使用Java类替代配置文件,开启了Spring快速开发赛道## 为什么要使用 **Spring** 框架? Spring 是一个轻量级应用框架,它提供了 IoC 和 AOP 这两个核心的功能。它的核心目的是为了…...
计算机网络-----详解HTTP协议
✏️1. 什么是HTTP HTTP (全称为 “超⽂本传输协议”) 是⼀种应⽤⾮常⼴泛的应⽤层协议(所谓 “超⽂本” 的含义, 就是传输的内容不仅仅是⽂本(⽐如 html, css 这个就是⽂本), 还可以是⼀些其他的资源, ⽐如图⽚, 视频, ⾳频等⼆进制的数据)。 HTTP 诞⽣…...
解决npm安装依赖报错ERESOLVE unable to resolve dependency tree
在使用 npm 安装项目依赖时,有时会遇到错误信息 “npm ERR! code ERESOLVE”,该错误通常发生在依赖版本冲突或者依赖解析问题时。本文将详细介绍出现这个错误的原因,并提供解决方法,确保正确安装项目依赖并避免该错误的发生。 一…...
微信小程序安卓手机输入框文字飘出输入框
最近在开发微信小程序遇到一个问题,安卓手机输入框文字飘出输入框,但是ios系统的手机则正常。 使用情景:做了一个弹窗,弹窗内是表单,需要填写一些信息,但是在填写信息时光标不显示,输入的内容飘…...
python网络自动化-数据格式与数据建模语言
数据格式 在Python网络运维自动化最基本是JSON、YAML和XML这3种数据格式。除了这3种常用的数据格式,还有一种深受网络工程师喜爱且在网络运维自动化中常用的数据承载方式——表格 需要注意的是JSON的键必须用双引号包裹,JSON的对象数据键值对的值和数组…...
C++ 中的 atan2 函数:深入解析与应用
在 C 编程中,数学计算是许多应用场景的核心,例如几何问题、物理模拟和游戏开发等。atan2 函数作为数学库中的一个重要工具,提供了比普通反正切函数更强大的功能。本文将深入解析 atan2 函数的原理、使用方法以及实际应用场景,并通…...
云计算-Azure Functions :构建事件驱动的云原生应用报告
云计算导论 课程研究报告 Azure Functions :构建事件驱动的云原生应用 摘要: Azure Functions 是一种无服务器解决方案,是由微软 Azure 平台提供的,可以使用户专注于业务逻辑,减少代码的编写,减少需要维护…...
【笔记——李沐动手学深度学习】2.3 线性代数
2.3.1 标量 标量由只有一个元素的张量表示。 下面的代码将实例化两个标量,并执行一些熟悉的算术运算,即加法、减、乘法、除法和指数。 2.3.2 向量 人们通过一维张量表示向量。一般来说,张量可以具有任意长度,取决于机器的内存限…...
多个 Job 并发运行时共享配置文件导致上下文污染,固化 Jenkins Job 上下文
基于 context.py 固化 Jenkins Job 上下文的完整方案,适用于你当前的工作流(Python Jenkins Pipeline),解决: 多个 Job 并发运行时共享配置文件导致上下文污染;读取环境变量或 JSON 文件时被其他 Job 修改…...
github 上的php项目
github 上的php项目 项目的网址 (Loong1996/LikeGirlSite: 情侣网站、情侣网页、恋爱记录网站) # 修改 # admin/Config_DB.php//localhost 为数据库地址 一般使用默认的即可 或(127.0.0.1) $db_address "mysql_php";/…...
防火墙快速管理软件,66K超小巧
软件介绍 今天为大家推荐一款轻量级的Windows防火墙管理工具,这款工具能帮助用户快速开启或关闭系统防火墙功能,操作比系统原生设置更加便捷高效。 软件优势 相比通过系统设置层层点击的操作方式,这款仅66KB大小的微型工具只需单击按钮…...
入门级STM32F103C8T6无人机遥控(原理图)
一、STM32主控电路 一、STM32 主控电路 把 STM32 想象成 “机器人的大脑”,核心电路是 “大脑的基础保障”:让大脑有电、有心跳(时钟 )、能复活(复位 )。 1. 电源引脚(VDD、VDDA、VSS 等 &#…...
无人机灯光驱动模块技术解析
一、运行方式 1. 核心流程: 指令接收:灯光控制模块通过无线通信链路(如WiFi, 数传电台,或专用的表演控制链路)接收来自地面站或中央控制系统的灯光指令。指令包含:颜色(RGB/RGBW值࿰…...
React + Umi(Umijs/Max) 搭建项目及配置
文章标题 01 环境准备02 快速构建2.1 参数选项2.2 umix 还是 umijs/max2.3 使用 pnpm (推荐)2.4 使用 npm 和 yarn2.5 启动项目2.6 启用 Prettier(可选)2.7 打包部署发布 03 Tailwind CSS 插件(可选)3.1 安…...
React 第六十四节Router中HashRouter的使用详细介绍及案例分析
前言 HashRouter 是 React Router 提供的一种路由实现方案,它使用 URL 的 hash 部分(# 后面的内容)来实现客户端路由功能。 一、HashRouter 的核心用途 客户端路由:在不刷新页面的情况下管理应用导航兼容性:支持不支…...
Linux RDMA网络配置手册
一、配置前准备工作 在进行 RDMA 网络配置之前,请确保以下准备工作已完成: 硬件环境 确保服务器支持 RDMA 功能,例如支持 InfiniBand 或 RoCE(RDMA over Converged Ethernet)的网卡。确保网络交换设备支持 RDMA 协议…...
sentinel与seata组件在微服务中的基本作用
微服务基础内容: 在微服务中,首先学习了微服务的横向拆分与纵向拆分,纵向拆分指按照功能拆分模块,横向拆分指将高复用的模块单独拆分,使纵向拆分的模块去调用这部分内容。 学习了基本拆分后,需要知道微服…...
Springboot 集成多数据源pgSql+mysql,启动报错
一.错误信息: 2025-06-25 20:25:50.870 ERROR [ai-manage-center,,] --- [ruid-ConnectionPool-Create-1057240219] DruidDataSource : create connection SQLException, url: jdbc:postgresql://10.10.60.227:5432/ai_dify1?sslmodedisable¤tSchemapub…...
南宫28NG相信品牌力量/Vue 3 中的组合式 API(Composition API)进阶实战
南宫28NG相信品牌力量【罔丨止:MGTY.PW】 点击此处复制到浏览器打开 随着 Vue 3 的普及,Composition API 已成为现代 Vue 开发的主流。本节我们将深入掌握组合式 API 的进阶用法,涵盖响应式工具、生命周期钩子封装、自定义逻辑抽离等关键技术…...
实战使用 Docker Compose 搭建 Redis Cluster 集群
文章目录 前言技术积累Docker Compose简介Redis Cluster简介Redis Cluster 解决的问题 实战演示部署环境创建目录编写Redis配置文件编写Docker-Compose.yml执行yml文件,启动容器查看容器状态创建集群验证集群集群数据验证 总结 前言 随着互联网技术的发展ÿ…...
Tauri(2.5.1)+Leptos(0.8.2)开发自用桌面小程序--DeepSeek辅助编程(俄罗斯方块)
在之前工作基础上(Tauri(2.5.1)Leptos(0.8.2)开发自用桌面小程序-CSDN博客),继续进行自用桌面小程序的开发,这次完全使用DeepSeek辅助编程做一个俄罗斯方块游戏,大部分代码由DeepSeek自主完成,Bug扔给DeepS…...
flex布局实例:把色子放进盒子里
目录 一、flex布局实例:把色子放进盒子里 1、基础样式 二、justify-content 属性 三、flex-direction 属性 四、align-items 属性 五、flex-wrap 属性 二、flex布局应用到常见场景 非常详细的讲解flex布局,看一看,练一练! …...
【启发式算法】RRT*算法详细介绍(Python)
📢本篇文章是博主人工智能(AI)领域学习时,用于个人学习、研究或者欣赏使用,并基于博主对相关等领域的一些理解而记录的学习摘录和笔记,若有不当和侵权之处,指出后将会立即改正,还望谅…...
基于R语言的亚组分析与森林图绘制1
亚组分析是临床研究中的重要分析方法,其核心是通过将研究对象按基线特征(如年龄、性别或吸烟状况等)划分为不同亚组,进而评估干预措施或暴露因素在各亚组中对结局影响的差异性。 在亚组分析中,交互作用(P for interaction)是关键指标,用于判断干预措施或暴露因素与亚组…...
idea, CreateProcess error=206, 文件名或扩展名太长
idea, CreateProcess error206, 文件名或扩展名太长 解决 “CreateProcess error206, 文件名或扩展名太长” 错误 CreateProcess error206 是 Windows 系统特有的错误,表示命令行参数超出了 Windows 的 32767 字符限制。这个问题在 Java 开发中尤其常见,…...
aspose.word在IIS后端DLL中高并发运行,线程安全隔离
aspose.word在IIS后端DLL中运行,加载很慢,如何为全部用户加载,再每个用户访问时在各自线程中直接可以打开WORD文件处理 Aspose.Words 在 IIS 中优化加载性能方案 针对 Aspose.Words 在 IIS 后端 DLL 中加载缓慢的问题,我们可以通过单例模式预加载组件并结合线程安…...
day042-负载均衡与web集群搭建
文章目录 0. 老男孩思想-面试官问:你对加班的看法?1. 负载均衡2. 搭建负载均衡的WordPress集群2.1 负载均衡服务器2.2 配置web服务器2.3 测试 踩坑记录1. /var/cache/nginx权限问题 0. 老男孩思想-面试官问:你对加班的看法? 互联网公司没有不加班的&a…...
DuDuTalk | 武汉赛思云科技有限公司通过武汉市人工智能企业认定!
近日,2025年武汉市人工智能企业名单正式公布!武汉赛思云科技有限公司(以下简称赛思云科技)凭借卓越的技术实力与创新成果,成功入选武汉市人工智能企业。这是对公司长期深耕AI语音智能领域、推动数字化转型的高度认可&a…...
Tita CRM飞书协同版:解锁企业销售与交付管理新效能
数字化转型的破局之道 在数字经济加速发展的今天,传统管理模式正面临前所未有的挑战: • 销售过程缺乏可视化管控手段 • 项目执行存在严重的信息孤岛 • 跨部门协作效率持续低下 • 绩效考核缺乏客观数据支撑 Tita CRM作为专业的智能化管理平台&#x…...
web安全之h2注入系统学习
起初是在N1 Junior 2025 上面碰到一题,考点是h2的sql注入。由于之前没有见过,趁此机会系统学习一番 实验代码 public class H2Inject {public static void main(String[] args) throws Exception{JdbcDataSource dataSource new JdbcDataSource();dataS…...
LVS-DR负载均衡群集深度实践:高性能架构设计与排障指南
目录 一、核心原理与理论 二、背景与架构设计 三、全流程部署步骤 1. NFS共享存储配置(192.168.7.100) 2. Real Server节点配置(四台服务器) 3. Director服务器配置 四、常见问题解决方案 五、生产环境总结 拓扑示意图&am…...
Java如何导出word(根据模板生成),通过word转成pdf,放压缩包
<!-- 导出word文档所需依赖--><dependency><groupId>com.deepoove</groupId><artifactId>poi-tl</artifactId><version>1.10.0-beta</version></dependency><dependency><groupId>org.apache.poi</gr…...
.NET 7.0 EF Core:一、创建Web API 项目基础框架和用户表的增删改查
demo 地址: https://github.com/iotjin/Jh.Admin.NETCore 代码不定时更新,请前往github查看最新代码 .NET 7.0 EF Core:一、创建Web API项目 官方教程序一、项目目录结构各层职责说明1️⃣ Admin.NETCore.API(接口层)2️⃣ Admin.…...
一篇文章了解XML
一、什么是 XML? XML 是一种结构化数据的标记语言,用来存储、传输和描述数据。 它和 HTML 很像,但它的标签是自定义的,不限定格式和外观,而是强调数据的结构和含义。 XML不是用来展示数据的,HTML是用来展…...
Windows下安装zookeeper
有关Linux安装zk的文章可以参考下我之前写的: Zookeeper 3.8.4 安装和参数解析 Windows下的下载和Linux是一样的,都是同一个包,目前zk稳定版是 3.8.4 下载解压后 在根目录下创建 data 文件夹用来存放数据文件 在 conf 文件夹中,…...
计算机网络 网络层:控制平面
在本章中,包含网络层的控制平面组件。控制平面作为一种网络范围的逻辑,不仅控制沿着从源主机到目的主机的端到端路径间的路由器如何转发数据报,而且控制网络层组件和服务如何配置和管理。5.2节,传统的计算图中最低开销路径的路由选…...
探索阿里云智能媒体管理IMM:解锁媒体处理新境界
一、引言:开启智能媒体管理新时代 在数字化浪潮的席卷下,媒体行业正经历着前所未有的变革。从传统媒体到新媒体的转型,从内容生产到传播分发,每一个环节都在寻求更高效、更智能的解决方案。而云计算,作为推动这一变革…...
微信点餐小程序—美食物
本项目是基于WAMP Server 和PHP 动态网页技术构建的微信小程序点餐系统,该系统主要分为前端(微信小程序)和后端(基于PHPMySQL服务器端) 整体架构流程 1、前端部分 用户界面:展示菜品、处理用户点餐操作、…...
Python零基础入门到高手8.5节: 实现选择排序算法
目录 8.5.1 排序算法简介 8.5.2 选择排序算法 8.5.3 好好学习,天天向上 8.5.1 排序算法简介 所谓排序,是指将数据集合中的元素按从小到大的顺序进行排列,或按从大到小的顺序进行排列。前者称为升序排序,后者称为降序排序。在数…...
JavaEE初阶第四期:解锁多线程,从 “单车道” 到 “高速公路” 的编程升级(二)
专栏:JavaEE初阶起飞计划 个人主页:手握风云 目录 一、Thread类及常用方法 2.1. Thread的常见构造方法 2.2. Thread的常见属性 2.3. 启动一个线程 2.4. 中断一个线程 2.5. 等待一个线程 2.6. 休眠当前线程 一、Thread类及常用方法 2.1. Thread的…...
Metasploit常用命令详解
一、Metasploit 概述 Metasploit是一款开源的渗透测试框架,由 H.D. Moore 于 2003 年首次发布,目前由 rapid7 公司维护。它整合了大量漏洞利用模块、后渗透工具和漏洞扫描功能,已成为网络安全工程师、红队 / 蓝队成员及安全研究人员的核心工…...
2025.6.24总结
今天发生了两件事,这每件事情都足以影响我的工作状态。 1.团队中有人要转岗 这算是最让我有些小震惊的事件了。我不明白,那个同事干得好好的,为啥会转岗,为啥会被调到其他团队。虽然团队有正编,有od,但我自始自终觉得…...
2023年全国青少年信息素养大赛Python 复赛真题——玩石头游戏
今日python每日练习题为——玩石头游戏,大家记得坚持刷题哦,闯入国赛~ 每轮可拿 1-3 块石头,双方均采取最优策略。若石头数 n 为 4 的倍数,无论先手取 k 块(1≤k≤3),后手总能取 4-k 块…...
MySQL之SQL性能优化策略
MySQL之SQL性能优化策略 一、主键优化策略1.1 主键的核心作用1.2 主键设计原则1.3 主键优化实践 二、ORDER BY优化策略2.1 ORDER BY执行原理2.2 ORDER BY优化技巧2.3 处理大结果集排序 三、GROUP BY优化策略3.1 GROUP BY执行原理3.2 GROUP BY优化方法 四、LIMIT优化策略4.1 LIM…...
AI时代工具:AIGC导航——AI工具集合
大家好!AIGC导航是一个汇集多种AIGC工具的平台,提供了丰富的工具和资源。 工具功能: 该平台整合了多样的AIGC工具,涵盖了绘画创作、写作辅助以及视频制作等多个领域。绘画工具能够生成高质量的图像作品;写作工具支持从构思到润色的全流程写…...
性能测试-jmeter实战4
课程:B站大学 记录软件测试-性能测试学习历程、掌握前端性能测试、后端性能测试、服务端性能测试的你才是一个专业的软件测试工程师 性能测试-jmeter实战4 jmeter环境搭建1. 安装Java环境(必需) JMeter环境搭建完整指南1. 安装Java࿰…...
C++字符串的行输入
1、字符串的输入 下面用一个真实的示例来进行演示: #include<iostream> #include<string>int main() {using namespace std;const int ArSize 20;char name[ArSize];char dessert[ArSize];cout << "Enter your name:\n";cin >>…...