Tabs
当需要对页面内容进行分开展示时,为了用户把关注点聚焦到当前页面,需要对页面内容进行分类,提高用户体验及页面的合理利用。Tabs组件可以在一个页面中实现快速切换,提高用户查找信息的效率。
Tabs-容器组件-组件参考(基于ArkTS的声明式开发范式)-ArkTS API参考-HarmonyOS应用开发
Tabs属性
barPosition
设置Tabs的页签位置(方向),默认值:BarPosition.Start
| 名称 | 描述 |
|---|---|
| Start | vertical属性方法设置为true时,页签位于容器左侧;vertical属性方法设置为false时,页签位于容器顶部。 |
| End | vertical属性方法设置为true时,页签位于容器右侧;vertical属性方法设置为false时,页签位于容器底部。 |
index
设置当前显示页签的索引,默认值:0
controller
设置Tabs控制器
布局方式
Tabs组件包含两部分,即TabBar和TabContent。TabBar是标签区域,TabContent是内容区域,设置不同的导航类型,那么布局也是不一样的,可以分别设置为顶部导航栏、底部导航栏、左侧导航栏和右侧导航栏。
顶部布局
@Entry
@Component
struct Index {
// 导航数组
@State list:string[] = ["首页","分类","应用","我的"]
build() {
Column() {
Tabs({barPosition:BarPosition.Start}){
ForEach(this.list,(item)=>{
TabContent(){
Text(`${item}内容`)
}.tabBar(item)
})
}
.vertical(false)
}
.height('100%')
}
}
结果如下:
底部布局
@Entry
@Component
struct Index {
// 导航数组
@State list:string[] = ["首页","分类","应用","我的"]
build() {
Column() {
Tabs({barPosition:BarPosition.End}){
ForEach(this.list,(item)=>{
TabContent(){
Text(`${item}内容`)
}.tabBar(item)
})
}
.vertical(false)
}
.height('100%')
}
}
结果如下:
左侧布局
@Entry
@Component
struct Index {
// 导航数组
@State list:string[] = ["首页","分类","应用","我的"]
build() {
Column() {
Tabs({barPosition:BarPosition.Start}){
ForEach(this.list,(item)=>{
TabContent(){
Text(`${item}内容`)
}.tabBar(item)
})
}
.vertical(true)
}
.height('100%')
}
}
结果如下:
右侧布局
@Entry
@Component
struct Index {
// 导航数组
@State list:string[] = ["首页","分类","应用","我的"]
build() {
Column() {
Tabs({barPosition:BarPosition.End}){
ForEach(this.list,(item)=>{
TabContent(){
Text(`${item}内容`)
}.tabBar(item)
})
}
.vertical(true)
}
.height('100%')
}
}
结果如下:
限制导航栏滑动切换
当我们在开发某些功能的时候,有的场景需要使用到滑动切换页面来聚焦内容,而有的场景是通过切换选项卡来聚焦内容。所以这里使用到scrollable属性来设置是否限制导航栏滑动切换操作。
scrollable:设置为true时可以通过滑动页面进行页面切换,为false时不可滑动切换页面。默认值:true
不限制滑动切换
拖动页面会切换到不同的导航栏
@Entry
@Component
struct Index {
@State message: string = 'Hello World'
build() {
Column() {
Tabs({barPosition:BarPosition.Start}){
...
}
.vertical(false)
.scrollable(true)
}
.height('100%')
}
}
限制滑动切换
拖动页面不会切换导航栏
@Entry
@Component
struct Index {
@State message: string = 'Hello World'
build() {
Column() {
Tabs({barPosition:BarPosition.Start}){
...
}
.vertical(false)
.scrollable(false)
}
.height('100%')
}
}
滚动导航栏
滚动导航栏需要设置tabs的borMode属性,默认设置是BarMode.Fixed,所有TabBar平均分配barWidth宽度,所以导航栏固定。设置为BarMode.Scrollable,每一个TabBar均使用实际布局宽度,超过总长度(横向Tabs的barWidth,纵向Tabs的barHeight)后可滑动。
@Entry
@Component
struct Index {
// 导航数组
@State list:string[] = ["新闻","财经","科技","体育","娱乐","汽车","博客"]
build() {
Column() {
Tabs({barPosition:BarPosition.Start}){
ForEach(this.list,(item)=>{
TabContent(){
Text(`${item}内容`)
}.tabBar(item)
})
}
.barWidth('80%')//横向Tabs的barWidth的宽度
.barMode(BarMode.Scrollable)
}
.height('100%')
}
}
结果如下: 拖动导航栏区域可以滑动导航栏
自定义导航栏
当tabs组件不满足我们开发各式各样需求的时候,官方也是支持自定义导航栏的,设置tabBar支持自定义函数组件@Builder,例如如下,自定义组件TabBuilder,传入要显示的参数(可根据自己的方式灵活传入),根据currentIndex字段来控制当前导航栏切换到第几个页面,渲染第几个页面的UI界面
@Entry
@Component
struct Index {
// 导航数组
@State list:string[] = ["首页","分类","应用","我的"]
// 未选中颜色
@State fontColor: string = '#182431'
// 选中颜色
@State selectedFontColor: string = '#007DFF'
// 当前活动页面
@State currentIndex: number = 0
// 控制器
private controller: TabsController = new TabsController()
// 自定义导航栏
@Builder TabBuilder(index: number, name: string) {
Column() {
Image($r('app.media.icon')).width(25).height(25).margin({bottom:5})
Text(name)
.fontColor(this.currentIndex === index ? this.selectedFontColor : this.fontColor)
.fontSize(12)
}
.width('100%')
.padding({top:5})
.border({width:{top:1},color:"#e3e3e3"})
}
build() {
Column() {
Tabs({barPosition:BarPosition.End, controller: this.controller}){
ForEach(this.list,(item,index)=>{
TabContent(){
Text(`${item}内容`)
}.tabBar(this.TabBuilder(index,item.toString()))
})
}
.onChange((index: number) => {
this.currentIndex = index
})
}
.height('100%')
}
}
结果如下:
切换导航栏改变页面数据
默认的tabs组件是一开始就初始化所有导航栏页面,当我们需要在切换后再渲染内容或调用接口,那么页面是不会再执行初始化操作,所以接下来就实现切换后能到达再次渲染内容或调用接口的效果
在这里我们会使用到@State装饰器和@Link装饰器来进行父子组件数据同步,使用@Watch监听状态改变
1、创建自定义组件
创建view目录及article.ets、category.ets、home.ets和user.ets四个ets文件
注:页面内容会有报错,不要着急,下一步就编写主ets文件内容
home.ets页面内容
@Component
export struct Home{
// 监听currentIndex字段
@Link @Watch('onCurrentIndex') currentIndex: number;
@State message:string = "默认内容"
// 监听currentIndex改变
onCurrentIndex(){
if(this.currentIndex==0){
this.message = `当前第几个活动页面:${this.currentIndex},改变默认内容`
}
}
build(){
Column(){
Text(this.message)
}
}
}
article.ets页面内容
@Component
export struct Article{
// 监听currentIndex字段
@Link @Watch('onCurrentIndex') currentIndex: number;
@State message:string = "默认内容"
// 监听currentIndex改变
onCurrentIndex(){
if(this.currentIndex==1){
this.message = `当前第几个活动页面:${this.currentIndex},改变默认内容`
}
}
build(){
Column(){
Text(this.message)
}
}
}
category.ets页面内容
@Component
export struct Category{
// 监听currentIndex字段
@Link @Watch('onCurrentIndex') currentIndex: number;
@State message:string = "默认内容"
// 监听currentIndex改变
onCurrentIndex(){
if(this.currentIndex==2){
this.message = `当前第几个活动页面:${this.currentIndex},改变默认内容`
}
}
build(){
Column(){
Text(this.message)
}
}
}
user.ets页面内容
@Component
export struct User{
// 监听currentIndex字段
@Link @Watch('onCurrentIndex') currentIndex: number;
@State message:string = "默认内容"
// 监听currentIndex改变
onCurrentIndex(){
if(this.currentIndex==3){
this.message = `当前第几个活动页面:${this.currentIndex},改变默认内容`
}
}
build(){
Column(){
Text(this.message)
}
}
}
2、pages/Index.ets文件内容如下
import { Home } from '../view/home'
import { Article } from '../view/article'
import { Category } from '../view/category'
import { User } from '../view/user'
@Entry
@Component
struct Index {
// 当前活动页面
@State currentIndex: number = 0
// 控制器
private controller: TabsController = new TabsController()
build() {
Column() {
Tabs({barPosition:BarPosition.End, controller: this.controller}){
TabContent() {
Home({currentIndex:$currentIndex})
}
.tabBar(this.TabBuilder(0,'首页'))
TabContent() {
Article({currentIndex:$currentIndex})
}
.tabBar(this.TabBuilder(1,'分类'))
TabContent() {
Category({currentIndex:$currentIndex})
}
.tabBar(this.TabBuilder(2,'文章'))
TabContent() {
User({currentIndex:$currentIndex})
}
.tabBar(this.TabBuilder(3,'我的'))
}
.onChange((index: number) => {
this.currentIndex = index
})
}
.height('100%')
}
// 自定义导航栏
@Builder TabBuilder(index: number, name: string) {
Column() {
Image($r('app.media.icon')).width(25).height(25).margin({bottom:5})
Text(name)
.fontColor(this.currentIndex === index ? '#007DFF' : '#182431')
.fontSize(12)
}
.width('100%')
.padding({top:5})
.border({width:{top:1},color:"#e3e3e3"})
}
}
结果: 当我们切换导航栏选项时,会同步currentIndex的内容,然后监听到currentIndex是否有改变,如果有改变则进行再次渲染内容或自定义方法等操作。
默认加载
切换监听