鸿蒙应用开发从入门到入行
第八天 - Tabs选项卡
导读:在本篇文章里,您将掌握使用Tabs选项卡做栏目分类,这是未来应用开发中极为常用的组件
- 首先说一声抱歉,比较忙很久没更新了。但放心吧,目前该忙的事已经忙完,后面会恢复更新频率。以及后续有计划出一套免费视频教程,敬请期待!
Tabs介绍
你是否经常在移动端应用里见到如下菜单分类,例如下面两图
<img src="https://gitee.com/xpzll/newtypora/raw/master/noteimg/202412061118373.png" alt="image-20241206085145419" style="zoom: 33%;" />
<img src="https://gitee.com/xpzll/newtypora/raw/master/noteimg/202412061118375.png" alt="image-20241206085448043" style="zoom: 33%;" />
- 像这样的不管是在上,还是在下的菜单分栏功能,在HarmonyOS应用开发中都是可以使用Tabs组件实现
每当某个Tabs里的菜单切换后,页面内容也会跟着改变,如下图
<img src="https://gitee.com/xpzll/newtypora/raw/master/noteimg/202412061118376.gif" alt="gif" style="zoom:33%;" />
- 也即:Tabs组件可以在一个页面内快速实现视图内容的切换
- 具体怎样使用呢?我们接着往下看
Tabs - 组件基本使用
- 首先,Tabs里面只能放
TabContent
子组件(放其他组件会报错),有多少个TabContent,就意味着有多少个切换视图。
- 如上图所示,这段代码里
Tabs
放了三个TabContent
,因此有三个视图进行切换。但此时仅能实现左滑才能切换,根本没有显示出“导航栏”,所以一般情况下还会给TabContent
设置tabBar
属性,用来设置对应的导航栏 如下代码,给每个TabContent都设置了tabBar属性
@Entry @Component struct Index { build() { Tabs() { TabContent() { Text('1') }.tabBar('首页') TabContent() { Text('2') }.tabBar('联系人') TabContent() { Text('3') }.tabBar('我的') } } }
此时效果如下
<img src="https://gitee.com/xpzll/newtypora/raw/master/noteimg/202412061118378.png" alt="image-20241206092240968" style="zoom:33%;" />
小结:
- Tabs里只能放TabContent
- TabContent有多少个就意味着有多少个视图切换
- TabContent配合tabBar属性,即可设置导航栏标题,tabBar传入字符串,字符串是什么,标题即为什么
修改导航栏位置到底部
- 默认情况下,导航栏在页面上方,如果想把导航栏设置到页面底部显示,可以通过给
Tabs
传入参数barPosition
来实现 代码如下:
Tabs({ barPosition: BarPosition.End }) { // .... 省略里面的TabContent代码 }
此时界面效果如下图
<img src="https://gitee.com/xpzll/newtypora/raw/master/noteimg/202412061118379.png" alt="image-20241206093101358" style="zoom:33%;" />
- 如上代码所示:barPosition参数,需要传入BarPosition的枚举,这个枚举仅有两个值:Start与End,默认即为Start,代表在顶部,设置为End即为底部
修改导航栏位置到侧边
- 那么是不是只有顶部、底部两种位置呢?其实不然,还可以设置左侧或右侧,这里需要用到Tabs的一个属性,即为:
vertical
- 这个属性代表:是否垂直摆放导航栏,那换句话说即为是否竖着放(也即侧边放),默认为false即水平摆放。
我们试着把这个属性改为true,如下代码
Tabs({ barPosition: BarPosition.Start }) { // 省略里面的TabContent代码 } .vertical(true) .barWidth(80) .barBackgroundColor('#f00')
效果如下图
<img src="https://gitee.com/xpzll/newtypora/raw/master/noteimg/202412061118380.png" alt="image-20241206093927822" style="zoom:33%;" />
代码解释:
- 因为vertical属性设置为true,必然是在侧边摆放导航栏,但为什么是左边呢?因为Tabs的
barPosition
参数设置为Start(默认值),即为在左侧,所以如果barPosition
设置为BarPosition.End
,即为在右侧。 - barWidth是设置导航条的宽度(侧边方向是设置宽度)或高度(上下方向是设置高度)
- barBackgroundColor是设置导航条背景颜色,这里加背景色主要是为了让大家能看到我们设置的宽度生效了
- 因为vertical属性设置为true,必然是在侧边摆放导航栏,但为什么是左边呢?因为Tabs的
小结:
- 如果Tabs不设置vertical或者vertical设置为false,导航栏方向都是上下摆放,至于是上还是下跟barPosition有关,Start为上,End为下
- 如果Tabs设置了vertical为true,导航栏方向都是侧边摆放,至于是左还是右跟barPosition有关,Start为左,End为右
Tabs嵌套使用
很多时候我们的App应用场景其实需要顶部、底部都有导航栏,即整个App分为“首页”、“发现”、“推荐”
、“我的”四个部分,但是在“首页”里,又分为:关注、视频、游戏、数码、科技四个板块,如下图所示<img src="https://alliance-communityfile-drcn.dbankcdn.com/FileServer/getFile/cmtyPub/011/111/111/0000000000011111111.20241203140520.09722079742152534343961373818208:50001231000000:2800:75F03258D7C49FBD3473702CDC8AC5FBD4C28F9B58E2B0E9BCADEF0868DF4EA1.gif?needInitFileName=true?needInitFileName=true" alt="img" style="zoom:50%;" />
这时候就需要嵌套导航栏(在首页这个视图里再套一个Tabs),代码如下
Tabs({ barPosition: BarPosition.End }) { TabContent() { // 在首页这个视图里,又分为关注、视频、游戏、数码、科技四个切换分类 Tabs() { TabContent() { Text('关注的内容') }.tabBar('关注') TabContent() { Text('视频的内容') }.tabBar('视频') TabContent() { Text('游戏的内容') }.tabBar('游戏') TabContent() { Text('数码的内容') }.tabBar('数码') TabContent() { Text('科技的内容') }.tabBar('科技') } }.tabBar('首页') TabContent() { Text('发现的内容') }.tabBar('发现') TabContent() { Text('推荐的内容') }.tabBar('推荐') TabContent() { Text('我的内容') }.tabBar('我的') }
限制导航栏滚动
- 默认情况下所有的
Tabs
的导航都具备滚动的功能,但是当我们使用Tabs嵌套时,如上面的场景,会发现底部的导航栏有滚动,首页里嵌套的导航栏也有滚动。为了避免他们冲突,一般我们会让底部的大导航栏禁止滚动。 如何禁止滚动呢?
- 使用
scrollable
属性,设置为false即可
- 使用
例
Tabs({ barPosition: BarPosition.End }) { TabContent() { // 在首页这个视图里,又分为关注、视频、游戏、数码、科技四个切换分类 Tabs() { // 省略这个嵌套的代码 } }.tabBar('首页') TabContent() { Text('发现的内容') }.tabBar('发现') TabContent() { Text('推荐的内容') }.tabBar('推荐') TabContent() { Text('我的内容') }.tabBar('我的') } .scrollable(false)
自定义导航栏
我们很多应用的底部导航栏,其实一般除了标题文字外,还会附带图标,例如下图
- 这时候需要我们使用
@Builder
装饰器自定义导航栏的布局后,再传递给tabBar 如下代码
tabBuilder(title: string, icon: ResourceStr) { Column({ space: 2 }) { Image(icon) .width(30) Text(title) } .width('100%') .height(50) .justifyContent(FlexAlign.Center) }
- 这个Builder声明一个垂直布局的UI,上为图标,下为文字(标题),但此时这个Builder跟每个tabBar还没有任何关联,因此需要做调用绑定
代码如下
Tabs({ barPosition: BarPosition.End }) { TabContent() { // ... }.tabBar(this.tabBuilder('首页', $r('app.media.ic_public_home'))) TabContent() { // ... }.tabBar(this.tabBuilder('信息', $r('app.media.ic_public_comments'))) TabContent() { // ... }.tabBar(this.tabBuilder('相册', $r('app.media.ic_public_albums'))) TabContent() { // ... }.tabBar(this.tabBuilder('我的', $r('app.media.ic_public_contacts'))) }
此时得到效果如下图
<img src="https://gitee.com/xpzll/newtypora/raw/master/noteimg/202412061118381.png" alt="image-20241206101841435" style="zoom:33%;" />
- 我们会发现,不管点击哪一个,都不会有高亮效果。这是因为使用自定义导航栏后,需要自行在Builder里根据当前选中下标来判断显示不同的图标和颜色
综上所述,我们应该先声明一个状态变量,记录当前选中的索引
@State currentIndex: number = 0 // 默认为0,代表默认让第一个导航高亮
修改Builder,代码如下
@Builder tabBuilder(title: string, icon: ResourceStr, selectIcon: ResourceStr, index: number) { Column({ space: 2 }) { Image(this.currentIndex === index ? selectIcon : icon) .width(30) .fillColor(this.currentIndex === index ? '#0094ff' : '#000') Text(title) .fontColor(this.currentIndex === index ? '#0094ff' : '#000') } .width('100%') .height(50) .justifyContent(FlexAlign.Center) }
代码解释:
- 首先参数上新增了selectIcon与index,分别代表选中时要显示的图片,以及当前的tabBar自身索引
- 代码内根据我们记录的导航索引,与传入的当前tabBar自身索引做比较。相等就意味着当前tabBar被选中,所以让其使用选中的图片,以及设置选中的颜色。否则用默认的图片与颜色
效果如下
<img src="https://gitee.com/xpzll/newtypora/raw/master/noteimg/202412061118382.png" alt="image-20241206102612263" style="zoom:33%;" />
切换指定页签
- 此时我们发现,之前在不使用自定义导航栏时,默认的Tabs会实现切换逻辑,也即点谁谁高亮。但使用自定义导航栏后,发现点击导航栏没有切换高亮效果。
- 原因:自定义导航栏是根据我们的自定义Builder来决定显示状态的,如果需要高亮随之改变,就需要把我们声明的记录索引的状态变量进行修改,也即上面声明的
currentIndex
。此时因为currentIndex
一直是0,所以一直是第一个首页高亮。因此,我们需要页签改变时让currentIndex的值也跟着改变 这是需要用到
Tabs
提供的onChange
事件,监听索引变化,并将当前切换后的索引值赋值给currentIndex,代码如下Tabs({ barPosition: BarPosition.End }) { // 省略中间代码 } .onChange(index => { this.currentIndex = index })
以上利用
onChange
可以实现以外,其实在Next加入$$双向绑定后也能实现,做法是,只要将currentIndex与Tabs的index参数做双向绑定即可实现,代码如下Tabs({ barPosition: BarPosition.End, index: $$this.currentIndex }) { // 省略里面内容 }
- 使用双向绑定还有个好处是:如果将来需要用代码改变页签,只需要改
currentIndex
的值即可,例如:this.currentIndex = 2
即会切换到页签索引为2的导航
总结
- 今日主要讲解了Tabs的使用,Tabs是一种视图切换的组件。
- 默认情况下,Tabs是在顶部显示,如果要改位置可以通过barPosition参数来修改
- 如果需要展示在侧边,可以通过 vertical 属性设置为true来实现
- 如果需要带图带标题的自定义导航栏,可以用@Builder进行封装并传入tabBar
课后练习
判断题
- 当设置vertical为true时,导航栏在右侧显示
- 当Tabs的barPosition为End,vertical为false时,导航栏在右侧显示
简单题
- 请回答,直接设置Tabs的vertical为true,导航栏在哪显示?
预告:下一篇内容
- 下一篇将做个鸿蒙官网的经典案例:新闻数据,即本页一开始的图如下,敬请期待
<img src="https://gitee.com/xpzll/newtypora/raw/master/noteimg/202412061118373.png" alt="image-20241206085145419" style="zoom: 33%;" />
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。