HarmonyOS 鸿蒙Next中Navigation和Tabs底部导航栏问题

HarmonyOS 鸿蒙Next中Navigation和Tabs底部导航栏问题

问题描述

1、父页面跳转子页面后,底部导航栏仍旧显示

图片

代码如下:

父页面 A:

build() {
    Column() {
      Tabs({
        // 确保导航栏在底部
        barPosition: BarPosition.End,
        controller: this.tabsController
      }) {
        // 1、记工
        TabContent() {
          RecordHome()
        }
        .padding({ left: '12vp', right: '12vp' })
        .backgroundColor($r('sys.color.comp_background_gray'))
        .tabBar(this.TabBuilder($r('app.string.nav_tab_recordWork'), 0, $r('sys.symbol.doc_plaintext_and_pencil')))

        // 2、统计
        TabContent() {
          RecordHome()
        }
        .padding({ left: '12vp', right: '12vp' })
        .backgroundColor($r('sys.color.comp_background_gray'))
        .tabBar(this.TabBuilder($r('app.string.nav_tab_statistics'), 1, $r('sys.symbol.form')))

        // 3、社区
        TabContent() {
          RecordHome()
        }
        .padding({ left: '12vp', right: '12vp' })
        .backgroundColor($r('sys.color.comp_background_gray'))
        .tabBar(this.TabBuilder($r('app.string.nav_tab_community'), 2, $r('sys.symbol.ellipsis_message')))

        // 4、我的
        TabContent() {
          RecordHome()
        }
        .padding({ left: '12vp', right: '12vp' })
        .backgroundColor($r('sys.color.comp_background_gray'))
        .tabBar(this.TabBuilder($r('app.string.nav_tab_mine'), 3, $r('sys.symbol.person')))
      }
      .width('100%')
      .height('100%')
      .barHeight('50vp')
      .barMode(BarMode.Fixed)
      .onChange((index: number) => {
        // 该方法实现双向绑定,以处理非用户点击导致的导航栏变化
        this.currentIndex = index;
      })
    }
    .width('100%')
    .height('100%')
    .backgroundColor($r('sys.color.comp_background_gray'))
  }

父页面引用的 B 组件:

build() {
    Navigation(this.pageInfos) {
      Stack({ alignContent: Alignment.Bottom }) {
        Scroll() {
          Column() {
            // 记工概要
            Column() {
              // ... 省略
              // 记工项
              Column() {
                ForEach(this.recordWorkVM.getMockData(), (item: RecordWorkModel, index?: number) => {
                  RecordWorkItem({
                    recordData: item
                  }).onClick(() => {
                    // 跳转记工详情页
                    this.pageInfos.pushPathByName('recordDetail', item.id);
                  });
                }, (item: RecordWorkModel) => item.id);
              }
              .padding({ top: $r("app.float.component_interval_s"), bottom: $r("app.float.component_interval_s") });
            }
            .width('100%')
            .margin({ top: $r("app.float.component_interval_s"), bottom: $r("app.float.component_interval_s") })
            .padding($r("app.float.component_interval_s"))
            .borderRadius($r('app.float.component_radius_primary'))
            .backgroundColor(Color.White);

          }
          .width('100%')
          .backgroundColor($r('sys.color.comp_background_gray'))
        }
        .height('100%')
        .scrollBar(BarState.Off)
        .edgeEffect(EdgeEffect.Spring);

        // 悬浮菜单栏
        Button({ type: ButtonType.Circle }) {
          SymbolGlyph($r('sys.symbol.plus'))
            .fontSize($r('app.float.font_size_title_m'))
            .fontWeight(FontWeight.Bold)
            .renderingStrategy(SymbolRenderingStrategy.MULTIPLE_COLOR)
            .fontColor([$r('sys.color.icon_on_primary'), $r('sys.color.icon_on_secondary')]);
        }
        .onClick(() => {

        })
        .width($r("app.float.button_size_m"))
        .height($r("app.float.button_size_m"))
        .shadow({ radius: 10, color: Color.Gray })
        .margin({ bottom: $r('app.float.component_interval_m') })
        .backgroundColor($r('app.color.main_color'));
      }
      .width('100%')
      .height('100%')
    }
  }

详情页 C:

build() {
    NavDestination() {
      Text(this.recordId);
      Button('触发Info错误')
        .onClick(() => {
          ErrorService.showError(ErrorMode.INFO, $r('app.string.error_base'), this.getUIContext())
        });

      Button('触发Warn错误')
        .onClick(() => {
          ErrorService.showError(ErrorMode.WARN, $r('app.string.error_no_data'), this.getUIContext())
        });

      Button('触发Error错误')
        .onClick(() => {
          ErrorService.showError(ErrorMode.ERROR, $r('app.string.error_param'))
        });

      ErrorHandler();
    }
    .backgroundColor($r('sys.color.comp_background_gray'))
    .title($r('app.string.page_element_record_detail'))
    .onBackPressed(() => {
      // 弹出路由栈栈顶元素
      const popDestinationInfo = this.pageInfos.pop();
      console.info(`pop 返回值 ${JSON.stringify(popDestinationInfo)}`);
      return true;
    }).onReady((context: NavDestinationContext) => {
      // 获取已有路由堆栈
      this.pageInfos = context.pathStack;
    })
  }

2、通过官方文档:Tabs页面Navigation路由跳转的实现方式

得知,Navigation 要放在 Tabs 外层。如下:

build() {
    Column() {
      Navigation(this.pageInfos) {
        Tabs({
          // 确保导航栏在底部
          barPosition: BarPosition.End,
          controller: this.tabsController
        }) {
          // 1、记工
          TabContent() {
            RecordHome()
          }
          .padding({ left: '12vp', right: '12vp' })
          .backgroundColor($r('sys.color.comp_background_gray'))
          .tabBar(this.TabBuilder($r('app.string.nav_tab_recordWork'), 0, $r('sys.symbol.doc_plaintext_and_pencil')))
          // ... 省略
        }
      }
    }
}

但是首页,底部 Tabs 导航栏布局有问题,距离底部有很大一段距离:

图片

先感谢大佬,希望能解答我的疑惑,谢谢~


更多关于HarmonyOS 鸿蒙Next中Navigation和Tabs底部导航栏问题的实战教程也可以访问 https://www.itying.com/category-93-b0.html

4 回复

问题是用Tab组件包裹Navigation组件,跳转Navigation子组件并不会影响到外层的Tab组件,还是要Navigation组件包裹tab组件,然后Navigation组件包裹tab组件底部有一块空白的问题,你在Navigation组件加上一个.hideTitleBar(true)属性就可以了,像这样:

Navigation(this.pageStack){
      Column() {
        Tabs({
          barPosition: BarPosition.End,
          index: $$this.currentIndex
        }) {
          ForEach(this.tabList, (tab: string, index: number) => {
            TabContent() {
              MyPage()
            }
            .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM])
            .tabBar(this.tabBuilder(index, tab))
            .onWillShow(() => {
              console.log('willshow' + tab)
            })
            .onWillHide(() => {
              console.log('willhide' + tab)
            })
          })
        }
        .onChange((index: number) => {
          // currentIndex控制TabContent显示页签
          this.currentIndex = index;
          this.selectedIndex = index;
        })
      }
      .height('100%')
      .width('100%')
    }
    .navDestination(this.pageMap)
    .hideTitleBar(true)

更多关于HarmonyOS 鸿蒙Next中Navigation和Tabs底部导航栏问题的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


确实可以。不过我感觉用navgation作为底部导航栏的实现会更好一点。tabs作为一个页面内部的页签,

在HarmonyOS Next中,Navigation组件用于管理页面导航结构,Tabs组件实现底部导航栏。两者结合时,需通过Navigation的子组件Tabs定义底部栏,并使用NavDestination配置各导航目标页。确保Tabs的barPosition属性设置为底部,并通过TabContent关联对应页面内容。导航状态由NavController管理,切换标签页时自动更新页面栈。

在HarmonyOS Next中,Tabs组件作为Navigation的子组件时,底部导航栏出现间距是常见的布局问题。这是由于Navigation默认会为页面内容预留安全区域,包括状态栏和导航栏区域。

解决方案是在Navigation组件上设置hideTitleBar属性为true,并手动处理安全区域:

build() {
  Column() {
    Navigation(this.pageInfos) {
      Tabs({
        barPosition: BarPosition.End,
        controller: this.tabsController
      }) {
        // TabContent内容...
      }
      .width('100%')
      .height('100%')
      .barHeight('50vp')
      .barMode(BarMode.Fixed)
    }
    .hideTitleBar(true)  // 隐藏标题栏
    .navBarWidth('100%')
    .navBarHeight('100%')
  }
  .width('100%')
  .height('100%')
  .padding({ bottom: $r('app.float.safe_area_bottom') }) // 适配底部安全区域
}

关键点:

  1. hideTitleBar(true) 移除默认的标题栏占用空间
  2. 通过padding适配底部安全区域,避免内容被遮挡
  3. 确保Tabs的高度设置为100%以充分利用可用空间

这样调整后,底部Tabs导航栏将正确贴合屏幕底部,同时保持正常的页面跳转行为。

回到顶部