HarmonyOS NEXT的Navigation,跳转子页面后底部Tab不隐藏问题解决

问题复现

一直以来,首页的Tabs是这么用的:

TypeScript 复制代码
import Home from "../pages/home/Home"
import ZhiHu from "../pages/song/Song"
import Mine from "../pages/mine/Mine"

@Entry
@Component
struct Index {
  @State currentIndex: number = 0
  private controller: TabsController = new TabsController()

  // 只有被@Entry装饰的组件才可以调用页面的生命周期
  onPageShow() {
    console.info('Index onPageShow');
  }
  // 只有被@Entry装饰的组件才可以调用页面的生命周期
  onPageHide() {
    console.info('Index onPageHide');
  }

  // 只有被@Entry装饰的组件才可以调用页面的生命周期
  onBackPress() {
    console.info('Index onBackPress');
  }

  build() {
    Column() {
      Tabs({
        barPosition: BarPosition.End,
        controller: this.controller
      }) {
        TabContent() {
          Home()
        }.tabBar(this.TabBuilder('首页', 0, $r('app.media.icon_sort'), $r('app.media.icon_sort_default')))

        TabContent() {
          ZhiHu()
        }.tabBar(this.TabBuilder('原声', 1, $r('app.media.ks_selected'), $r('app.media.ks')))

        TabContent() {
           Mine()
        }.tabBar(this.TabBuilder('我的', 2, $r('app.media.user_selected'), $r('app.media.user')))
      }.scrollable(false) // 禁止滑动切换
    }
    .width('100%')
    .height('100%')
  }

  // 自定义导航页签的样式
  @Builder TabBuilder(title: string, targetIndex: number, selectedImg: Resource, normalImg: Resource) {
    Column() {
      Image(this.currentIndex === targetIndex ? selectedImg : normalImg)
        .size({ width: 25, height: 25 })
      Text(title)
        .fontColor(this.currentIndex === targetIndex ? '#28bff1' : '#8a8a8a')
    }
    .width('100%')
    .height(50)
    .justifyContent(FlexAlign.Center)
    .onClick(() => {
      this.currentIndex = targetIndex
      this.controller.changeIndex(this.currentIndex)
    })
  }
}

之前一直没留意到,跳转到 子页面后,这底部的几个tab竟然还在,没有隐藏掉。这是什么情况?其实是用法问题。

在元服务的也存在这个问题,之前Index页是这么写的:

TypeScript 复制代码
import Home from "./home/Home";
import Mine from "./mine/Mine";
import { AtomicServiceTabs, OnContentWillChangeCallback, TabBarOptions, TabBarPosition } from '@kit.ArkUI';
import { Log } from "../utils/logutil";
import { authentication } from "@kit.AccountKit";
import { BusinessError } from "@kit.BasicServicesKit";

@Entry
@Component
struct Index {
  // 组件生命周期
  aboutToAppear() {
    Log.info('Index aboutToAppear');
    this.loginWithHuaweiID();
  }

  // 组件生命周期
  aboutToDisappear() {
    Log.info('Index aboutToDisappear');
  }

  @State currentIndex: number = 0
  onContentWillChangeCallBack: OnContentWillChangeCallback = (currentIndex: number, comingIndex: number): boolean => {
    this.currentIndex = currentIndex;

    console.log('OnContentWillChangeCallback')
    return true;
  }
  onTabClick: Callback<number> = (index: number) => {

    console.log('onTabClick');
  }

  @Builder
  Mine() {
    Column() {
      Mine()
    }.width('100%').height('100%')
  }

  @Builder
  Home() {
    Column() {
      Home()
    }.width('100%').height('100%')
  }

  build() {
    Stack() {
      AtomicServiceTabs({
        tabContents: [
          () => {
            this.Home()
          },
          () => {
            this.Mine()
          },

        ],
        tabBarOptionsArray: [
          new TabBarOptions($r('sys.media.leave_home_fill'), '首页', Color.Black, Color.Blue),
          new TabBarOptions($r('sys.media.AI_pause'), '我的', Color.Black, Color.Blue),
        ],
        tabBarPosition: TabBarPosition.BOTTOM,
        barBackgroundColor: $r('sys.color.ohos_id_color_bottom_tab_bg'),
        onTabBarClick: this.onTabClick,
        onContentWillChange: this.onContentWillChangeCallBack,
      })
    }.height('100%')
  }
}
}

解决办法

在Index页面中,用Navigation把tabs包裹起来。然后,注意在tab的页面中,不要再用Navigation包裹了,只在这Index页这里保留一份。那么tab页的title呢?自己用个Text自定义实现就行啦。

那么tab页中,如何跳转到子页面呢?

然后重点来了,用@Provide装饰器和@Consume装饰器。

@Provide和@Consume,应用于与后代组件的双向数据同步,应用于状态数据在多个层级之间传递的场景。不同于上文提到的父子组件之间通过命名参数机制传递,@Provide和@Consume摆脱参数传递机制的束缚,实现跨层级传递。

其中@Provide装饰的变量是在祖先组件中,可以理解为被"提供"给后代的状态变量。@Consume装饰的变量是在后代组件中,去"消费(绑定)"祖先组件提供的变量。

@Provide/@Consume是跨组件层级的双向同步。

在Index页面用以下方式定义个pageStack。

TypeScript 复制代码
 @Entry
@Component
struct Index {
  @State currentIndex: number = 0
  private controller: TabsController = new TabsController()
  //定义pageStack
  @Provide pageStack: NavPathStack = new NavPathStack()
  //......
}

在tab的页面中,通过使用@Consume去获取@Provide提供的变量。

TypeScript 复制代码
@Component
export default struct Home {
  //Consume,去"消费(绑定)"祖先组件提供的变量
  @Consume pageStack: NavPathStack

  private swiperController: SwiperController = new SwiperController()
  private swiperData: SwiperDataSource<BannerItem> = new SwiperDataSource()

  //......
  this.pageStack.pushDestinationByName("MusicPlayerPage", { item:it }).catch((e:Error)=>{
                      // 跳转失败,会返回错误码及错误信息
                      console.log(`catch exception: ${JSON.stringify(e)}`)
                    }).then(()=>{
                      // 跳转成功
                    });
}

其他资源

相关推荐
京东云开发者8 小时前
81.8 秒的视频,我们改了 15 个版本:一次纯 Codex 驱动的 AI-native 视频实践
前端·aigc
OH_TPC8 小时前
【鸿蒙优选三方库】@react-native-ohos/react-native-svg:SVG 矢量图形渲染组件
华为·harmonyos·鸿蒙
Csvn8 小时前
TypeScript 大型项目架构:从单体 tsconfig 到分层可扩展的工程
前端
xiangyun619 小时前
【408数据结构 08】队列:循环队列判空判满,408年年考,一次讲清
c语言·开发语言·数据结构·c++·算法
xiangyun619 小时前
【408数据结构 06】双链表、循环链表、静态链表
c语言·开发语言·数据结构·c++·算法
计算机魔术师10 小时前
Dario Amodei 发文呼吁为前沿 AI 降速并提出三点计划
前端
计算机魔术师10 小时前
OpenAI的AI代理偷偷给RubyGems下毒,我们却毫无察觉
前端
甲维斯10 小时前
0代码,0建模,3句话开发一个3D游戏!
前端·游戏·游戏开发
李游Leo11 小时前
HarmonyOS 7 实战开发 01:搭建内容工作台基础框架
harmonyos
IT_陈寒11 小时前
Vue的响应式更新把我坑惨了,原来问题出在这
前端·人工智能·后端