管理中心
我的
您当前正在浏览新版开发者文档中心,目录分类和层级有所调整。点击左侧当前文档分类名称前的“☰”图标,可切换文档分类。 了解新版目录
问题处理与运维开发与测试问题应用框架开发UI框架组件使用如何设置TabBar布局

如何设置TabBar布局

问题现象

TabBar的布局效果可以根据不同的设计需求来实现多种样式。以下是一些常见的TabBar布局效果:

  • 场景一:如何实现不同方向的TabBar布局效果(如侧边垂直布局、底部水平布局等)?
  • 场景二:如何实现页签的居中或左右对齐的布局效果?
  • 场景三:如何实现TabBar左右分布的布局效果?
  • 场景四:如何实现每个页签宽度均不相同的布局效果?
  • 场景五:如何实现页签布局根据数量不同,进行动态调整的效果?

背景知识

  • Tabs组件:通过页签进行内容视图切换的容器组件,每个页签对应一个内容视图。
  • tabBar:设置TabBar上显示内容。

解决方案

本文将基于上述场景,逐一阐述其具体实现方式。

展开

问题场景

问题描述

解决方案

场景一

实现不同方向的TabBar布局效果。

通过barPosition属性和vertical属性,实现TabBar不同方向的布局。

场景二

实现页签的居中或左右对齐的布局效果。

通过barMode可以设置TabBar布局模式,再加上TabsOptions中的barModifier可以设置tabBar的align属性实现页签对齐布局效果。

场景三

实现TabBar左右分布的布局效果。

利用Stack组件自定义TabBar,再使用position属性自定义每一个页签的位置。则可实现页签不均匀分布的效果。

场景四

实现每个页签宽度均不相同的布局效果。

通过将barMode设置为BarMode.Scrollable可滚动模式,tabBar的宽度即可以根据实际宽度显示。

场景五

实现页签布局根据数量不同,进行动态调整的效果。

通过barGridAlign属性可以实现以栅格化方式设置TabBar的可见区域。将barGridAlign属性与页签个数相结合,即可达到动态调整页签布局的效果。

  • 场景一:实现不同方向的TabBar布局效果。

    可通过barPosition属性设置页签的位置,其取值为BarPosition.Start或BarPosition.End。默认值为BarPosition.Start,表示页签位于页面顶部;设置为End时,页签则显示在页面底部。

    此外,vertical属性用于控制页签的布局方向,默认值为false,表示横向布局(页签位于顶部或底部);当设为true时,页签变为纵向布局,显示在屏幕左侧或右侧。

    综上所述,可以得出下表结论:

    展开

    barPosition取值

    vertical取值

    TabBar位置

    BarPosition.Start(默认值)

    true

    屏幕左侧

    BarPosition.Start(默认值)

    false(默认值)

    屏幕顶部

    BarPosition.End

    true

    屏幕右侧

    BarPosition.End

    false(默认值)

    屏幕底部

    用TabBar位于屏幕左侧举例,实现代码如下:

    @Entry
    @Component
    struct TabBarLayoutInDifferentDirections {
      build() {
        Column() {
          Tabs({
            barPosition: BarPosition.Start
          }) {
            TabContent() {
              Column() {
                Text('首页');
              }.width('100%').height('100%')
              .justifyContent(FlexAlign.Center);
            }.tabBar('首页');
    
            TabContent() {
              Column() {
                Text('商城');
              }.width('100%').height('100%')
              .justifyContent(FlexAlign.Center);
            }.tabBar('商城');
    
            TabContent() {
              Column() {
                Text('我的');
              }.width('100%').height('100%')
              .justifyContent(FlexAlign.Center);
            }.tabBar('我的');
          }.vertical(true)
          .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM]);
        };
      }
    }

    实现效果如下:

    • 场景二:实现页签的居中或左右对齐的布局效果。

      通过barMode可以设置TabBar布局模式,再加上TabsOptions中的barModifier可以设置tabBar的align属性实现页签对齐布局效果。

      详情可参考示例:页签对齐布局。

    • 场景三:实现TabBar左右分布的布局效果。

      在某些应用场景中,开发者可能需要一个自定义的TabBar布局,其中左边的两个页签居左对齐,右边的两个页签居右对齐,而中间部分则可以放置一个图标或按钮。这种布局方式不仅能够有效利用屏幕空间,还能提供更灵活的导航和功能入口,提升用户体验。

      利用Stack组件自定义TabBar,再使用position属性自定义每一个页签的位置。则可实现页签不均匀分布的效果。

      实现代码如下:

      @Entry
      @Component
      export struct TabBarAlignLeftAndRight {
        currentIndex: number = 0;
        @State selectedIndex: number = 0;
        fontColor: string = '#000';
        selectedFontColor: string = '#0A59F7';
        tabName: Array<string> = ['首页', '商城', '更多', '我的'];
        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 });
          }
          .onClick(() => {
            this.controller.changeIndex(index);
            this.selectedIndex = index;
          })
          .padding(10)
          // 设置TabItem的相对位置
          .position(
            index === 1 ? { left: 80 } :
              index === 2 ? { right: 90 } :
                index === 3 ? { right: 0 } : {});
        }
      
        build() {
          Stack({ alignContent: Alignment.BottomStart }) {
            Tabs({
              barPosition: BarPosition.End,
              index: this.currentIndex,
              controller: this.controller
            }) {
              TabContent() {
                Column() {
                  Text('首页');
                }.width('100%').height('100%')
                .justifyContent(FlexAlign.Center);
              };
      
              TabContent() {
                Column() {
                  Text('商城');
                }.width('100%').height('100%')
                .justifyContent(FlexAlign.Center);
              };
      
              TabContent() {
                Column() {
                  Text('更多');
                }.width('100%').height('100%')
                .justifyContent(FlexAlign.Center);
              };
      
              TabContent() {
                Column() {
                  Text('我的');
                }.width('100%').height('100%')
                .justifyContent(FlexAlign.Center);
              };
            }
            .barHeight(0)
            .onAnimationStart((index: number, targetIndex: number) => {
              if (index === targetIndex) {
                return;
              }
              this.selectedIndex = targetIndex;
            });
      
            Stack() {
              // 用Row组件实现TabBar效果
              Row() {
                ForEach(this.tabName, (item: string, index: number) => {
                  this.tabBuilder(index, item);
                });
              }
              .justifyContent(FlexAlign.SpaceBetween)
              .alignItems(VerticalAlign.Bottom)
              .width('100%')
              .backgroundColor(Color.White);
      
              // 开发者按需设计中间宫格展示内容,该示例展示图标
              Image($r('app.media.startIcon')) // 资源地址请自行替换
                .width(25)
                .height(25)
                .align(Alignment.Bottom);
            };
          };
        }
      }

      实现效果如下:

    • 场景四:实现每个页签宽度均不相同的布局效果。

      通过将barMode设置为BarMode.Scrollable可滚动模式,tabBar的宽度即可以根据实际宽度显示。

      实现代码如下:

      @Entry
      @Component
      struct TabBarLayoutUnevenly {
        build() {
          Column() {
            Tabs() {
              TabContent() {
                Column() {
                  Text('首页');
                }.width('100%').height('100%')
                .justifyContent(FlexAlign.Center);
              }.tabBar('首页');
      
              TabContent() {
                Column() {
                  Text('一多适配');
                }.width('100%').height('100%')
                .justifyContent(FlexAlign.Center);
              }.tabBar('一多适配');
      
              TabContent() {
                Column() {
                  Text('HarmonyOS应用');
                }.width('100%').height('100%')
                .justifyContent(FlexAlign.Center);
              }.tabBar('HarmonyOS应用');
      
              TabContent() {
                Column() {
                  Text('实况窗');
                }.width('100%').height('100%')
                .justifyContent(FlexAlign.Center);
              }.tabBar('实况窗');
            }.barMode(BarMode.Scrollable);
          };
        }
      }

      实现效果如下:

      更多实现方式和详情可参考示例:如何给tabBar页签设置不同宽度。

    • 场景五:实现页签布局根据数量不同,进行动态调整的效果。

      通过barGridAlign属性可以实现以栅格化方式设置TabBar的可见区域。将barGridAlign属性与页签个数相结合,即可达到动态调整页签布局的效果。

      详情可参考示例:Tabs如何根据TabBar数量更改页签栏排布和设置TabBar栅格化可见区域。

常见FAQ

Q:为什么当barHeight与SubTabBarStyle.of同时设置的时候,文字会出现被部分覆盖的错误样式?

A:子页签的内边距默认值:{left:8.0vp,right:8.0vp,top:17.0vp,bottom:18.0vp}。SubTabBarStyle存在默认的内边距,使用时可以主动设置下:tabBar(SubTabBarStyle.of('文本').padding(0))。