MainPage.ets 里没有把四个 tab 写死在页面里,而是抽到了 TabsBarModel.ets。这个小设计很值得学,因为它让页面代码清爽很多。

项目源码:https://gitcode.com/HarmonyOS_Samples/SmartReach/tree/master

页面里只拿结果

主页面只写了这一句:

private tabsBar: BottomTabBarStyle[] = TabsBarModel.getTabBarByPage() ?? [];

然后在 HdsTabs 里循环:

Repeat(this.tabsBar).each((repeatItem: RepeatItem<BottomTabBarStyle>) => {
  TabContent() {
    WaterFlowView({
      currentTabIndex: repeatItem.index,
    })
  }
  .tabBar(repeatItem.item)
})

页面不关心图标怎么生成,也不关心选中态颜色怎么配。它只管拿到 BottomTabBarStyle[] 并渲染。

BAR_ITEMS 是原始配置

TabsBarModel.ets 里先定义了四个 tab:

const BAR_ITEMS: BarItem[] = [
  {
    label: $r('app.string.tab_home'),
    normalColor: $r('sys.color.icon_primary'),
    normalSymbolResource: $r('sys.symbol.house_fill'),
    selectedColor: $r('sys.color.icon_emphasize'),
    selectedSymbolResource: $r('sys.symbol.house_fill'),
  },
  {
    label: $r('app.string.tab_video'),
    normalColor: $r('sys.color.icon_primary'),
    normalSymbolResource: $r('sys.symbol.play_hexagon_fill'),
    selectedColor: $r('sys.color.icon_emphasize'),
    selectedSymbolResource: $r('sys.symbol.play_hexagon_fill'),
  }
]

Hand-drawn flowchart in ink-notes style detailing

真实文件里有四项:首页、视频、购物、我的。这里为了阅读只截两项。

SymbolGlyphModifier 负责图标样式

生成 tab 样式的核心代码是:

const tabBarStyle = new BottomTabBarStyle({
  normal: new SymbolGlyphModifier(item.normalSymbolResource)
    .renderingStrategy(SymbolRenderingStrategy.SINGLE)
    .fontColor([item.normalColor]),
  selected: new SymbolGlyphModifier(item.selectedSymbolResource)
    .renderingStrategy(SymbolRenderingStrategy.SINGLE)
    .fontColor([item.selectedColor])
}, item.label)
  .labelStyle({
    unselectedColor: item.normalColor,
    selectedColor: item.selectedColor,
  });

这段代码做了两套样式:普通状态和选中状态。图标用系统 symbol,颜色也用系统颜色资源。

为什么要缓存

TabsBarModel 里有一个缓存:

private static cachedTabBarStyleList?: BottomTabBarStyle[];

public static getTabBarByPage(): BottomTabBarStyle[] {
  if (!TabsBarModel.cachedTabBarStyleList) {
    const tabBarStyleList: BottomTabBarStyle[] = [];
    // 生成 BottomTabBarStyle
    TabsBarModel.cachedTabBarStyleList = tabBarStyleList;
  }
  return TabsBarModel.cachedTabBarStyleList;
}

这个缓存不是必须,但挺合理。Tab 样式通常不会频繁变化,生成一次复用就够了。

SCROLLER_LIST 也放在这里

文件最后还有:

export const SCROLLER_LIST: Scroller[] = new Array(4).fill(null).map(() => new Scroller());

每个 tab 对应一个 Scroller,后面 HdsNavigation 会绑定它:

.bindToScrollable(SCROLLER_LIST)

这样导航栏滚动效果和不同页签里的滚动区域就能关联起来。

写在最后

TabsBarModel 看起来只是个小文件,但它体现了一个很实用的思路:页面只负责渲染,配置和样式生成放到模型层。小项目这么写不麻烦,大项目这么写会救命。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐