Tabs组件可以在一个页面内快速实现视图内容的切换,一方面提升查找信息的效率,另一方面精简用户单次获取到的信息量
官方文档(指南)
https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V13/arkts-navigation-tabs-V13
对子组件的要求
不支持自定义组件作为子组件, 仅可包含子组件TabContent, 以及渲染控制类型if/else和ForEach, 并且if/else和ForEach下也仅支持TabContent, 不支持自定义组件。
基本布局
-
Tabs组件的页面组成包含两个部分,分别是TabContent和TabBar。
-
TabContent是内容页,
-
TabBar是导航页签栏,
-
根据不同的导航类型,布局会有区别,可以分为底部导航、顶部导航、侧边导航,
![[6f904c37-671e-4f24-ad8c-448603e04dd9.png]]
TypeScript
Tabs() {
//1. 首页
TabContent() {
Text('首页的内容').fontSize(30)
}
.tabBar('首页')
// 2. 推荐
TabContent() {
Text('推荐的内容').fontSize(30)
}
.tabBar('推荐')
// 3. 发现
TabContent() {
Text('发现的内容').fontSize(30)
}
.tabBar('发现')
// 4. 我的
TabContent() {
Text('我的内容').fontSize(30)
}
.tabBar("我的")
}
常用属性
TypeScript
// BarPosition.Start 顶部导航
// BarPosition.End 底部导航
Tabs({ barPosition: BarPosition.End }) {
// TabContent的内容:首页、发现、推荐、我的
...
}
// .barPosition(BarPosition.End) // 导航栏的位置
// .barWidth('80%') //导航栏的宽度
// .barHeight(30) //导航栏的高度
// .barBackgroundColor(Color.Green) // 导航栏的背景色
// .vertical(true) //垂直导航
// .scrollable(false) // 控制滑动切换
// .barMode(BarMode.Fixed) // tabBar固定,不可滚动
// .barMode(BarMode.Scrollable) //tabBar可以滚动
-
barMode属性
-
固定导航
TypeScript.barMode(BarMode.Fixed)
当内容分类较为固定且不具有拓展性时,例如底部导航内容分类一般固定,分类数量一般在3-5个,此时使用固定导航栏。固定导航栏不可滚动,无法被拖拽滚动,内容均分tabBar的宽度。
-
可滚动导航栏
TypeScript.barMode(BarMode.Scrollable)
滚动导航栏可以用于顶部导航栏或者侧边导航栏的设置,内容分类较多,屏幕宽度无法容纳所有分类页签的情况下,需要使用可滚动的导航栏,支持用户点击和滑动来加载隐藏的页签内容。
-
设置子页签的样式
TypeScript
Tabs() {
TabContent() {
Text("商品的内容").fontSize(16)
}
//给tabBar添加图标
// .tabBar(new BottomTabBarStyle($r('sys.media.ohos_app_icon'), '商品'))
//设置当前子页签的样式
.tabBar(SubTabBarStyle.of('商品')
.indicator({
color: Color.Red, //下划线颜色
height: 5, //下划线高度
width: 20, //下划线宽度
borderRadius: 2, //下划线圆角半径
marginTop: 12 //下划线与文字间距
})
.labelStyle({
selectedColor: '#f00', // 子页签选中时的颜色
unselectedColor: '#00f' // 子页签未选中时颜色
})
)
}
嵌套的Tabs
![[d95e39b5-03e8-456c-a089-cec715a621bd.png]]
![[4d6774ec-f39b-4d9c-b04f-93cf77b8ef55.png]]
TypeScript
// ----------------------------外层的Tabs
Tabs() {
TabContent() {
Text("商品的内容").fontSize(16)
}.tabBar("商品")
TabContent() {
// ---------------------嵌套的Tabs
Tabs() {
TabContent() {
Text("图书详情的内容").fontSize(16)
}.tabBar("图书详情")
TabContent() {
Text("出版信息的内容").fontSize(16)
}.tabBar("出版信息")
}
}.tabBar("详情")
TabContent() {
// ----------------------------嵌套的Tabs
Tabs() {
TabContent() {
Text("短评的内容").fontSize(16)
}.tabBar("短评")
TabContent() {
Text("长评的内容").fontSize(16)
}.tabBar("长评")
}
}.tabBar("评论")
TabContent() {
Text("推荐的内容").fontSize(16)
}.tabBar("推荐")
}
自定义导航栏
Tabs控制器
TypeScript
private controller: TabsController = new TabsController();
...
Tabs({ barPosition: BarPosition.End, controller: this.controller }) {
...
}
//监听tabContent的切换
.onChange((index: number) => {
})
//控制TabContent的切换
this.controller.changeIndex(index);
案例代码
TypeScript
import { LengthMetrics } from '@kit.ArkUI'
import { DetailDetail } from '../view/detail/DetailDetail'
import { ProductDetail } from '../view/detail/ProductDetail'
@Entry
@Component
struct Del {
// TabsController是系统提供的控制器类型
private controller: TabsController = new TabsController();
@State arr: number[] = [1, 2, 3, 4, 5, 6, 7, 8, 9]
@State activeIndex: number = 1
@State navList: string[] = ["商品", "详情", "评论", "推荐"]
build() {
Column() {
// 自定义tabBar
Row() {
Text("返回")
Flex({
justifyContent: FlexAlign.SpaceBetween
}) {
ForEach(this.navList, (item: string, index: number) => {
Column() {
Text(item)
.fontColor(this.activeIndex === index ? '#f00' : '#000')
.fontSize(this.activeIndex === index ? '20' : '16')
Divider()
.color('#f00')
.width('80%')
.visibility(this.activeIndex === index ? Visibility.Visible : Visibility.Hidden)
}
.onClick(() => {
this.activeIndex = index
//控制TabContent的切换
this.controller.changeIndex(index);
})
}, (item: string) => item)
}
.width(200)
// .border({ width: 1, color: '#f00' })
Text("...")
}
.width('100%')
.height(44)
.backgroundColor(Color.Orange)
.justifyContent(FlexAlign.SpaceBetween)
//Tabs
Tabs({ controller: this.controller }) {
TabContent() {
Text("商品的内容").fontSize(20).width('90%').height(100).border({ width: 1, color: '#f00' })
}
TabContent() {
Text("详情的内容").fontSize(20).width('90%').height(100).border({ width: 1, color: '#f00' })
}
TabContent() {
Text("评论的内容").fontSize(20).width('90%').height(100).border({ width: 1, color: '#f00' })
}
TabContent() {
Text("推荐的内容").fontSize(20).width('90%').height(100).border({ width: 1, color: '#f00' })
}
}
.barPosition(BarPosition.Start)
.vertical(false)
// .scrollable(false)
.barMode(BarMode.Fixed)
// 监听tabContent的切换
.onChange((index: number) => {
console.log(index.toString())
this.activeIndex = index
})
}
}
}
数据
JSON
[
{
unselectedImg: 'home',
selectedImg: 'activeHome',
title: '首页'
},
{
unselectedImg: 'star',
selectedImg: 'activeStar',
title: '动态'
},
{
unselectedImg: 'message',
selectedImg: 'activeMessage',
title: '消息'
},
{
unselectedImg: 'people',
selectedImg: 'activePeople',
title: '我的'
}
]
扩展作业
舵式底部导航
![[feebd23e-52db-4749-a80e-603210d4b137.png]]
数据
JSON
[
{
unselectedImg: 'home',
selectedImg: 'activeHome',
title: '首页',
middleMode: false
},
{
unselectedImg: 'star',
selectedImg: 'activeStar',
title: '动态',
middleMode: false
},
{
unselectedImg: 'activePlus',
selectedImg: 'activePlus',
title: '',
middleMode: true
},
{
unselectedImg: 'message',
selectedImg: 'activeMessage',
title: '消息',
middleMode: false
},
{
unselectedImg: 'people',
selectedImg: 'activePeople',
title: '我的',
middleMode: false
},
]