10.13 Tabs选项卡布局

Tabs组件可以在一个页面内快速实现视图内容的切换,一方面提升查找信息的效率,另一方面精简用户单次获取到的信息量

官方文档(指南)

https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V13/arkts-navigation-tabs-V13

对子组件的要求

不支持自定义组件作为子组件, 仅可包含子组件TabContent, 以及渲染控制类型if/elseForEach, 并且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
  },
]
相关推荐
我爱学习_zwj5 小时前
【鸿蒙进阶-7】鸿蒙与web混合开发
前端·华为·harmonyos
HMSCore8 小时前
消息推送策略:如何在营销与用户体验间找到最佳平衡点
harmonyos
HMSCore8 小时前
同一设备多账号登录,如何避免消息推送“串门”?
harmonyos
零點壹度ideality9 小时前
鸿蒙实现可以上下左右滑动的表格-摆脱大量ListScroller
前端·harmonyos
●VON10 小时前
重生之我在大学自学鸿蒙开发第七天-《AI语音朗读》
学习·华为·云原生·架构·harmonyos
Industio_触觉智能11 小时前
RK3576开发板/核心板应用分享之开源鸿蒙
鸿蒙·openharmony·嵌入式开发·开源鸿蒙·鸿蒙开发板·鸿蒙南向·xts
我是华为OD~HR~栗栗呀12 小时前
华为OD-21届考研-Java面经
java·前端·c++·python·华为od·华为·面试
君逸臣劳12 小时前
玩Android Harmony next版,通过项目了解harmony项目快速搭建开发
android·harmonyos
TrisighT12 小时前
鸿蒙与H5桥接通信技术深度解析
harmonyos