一、前言

在上一讲的鸿蒙开发之多样化底部导航栏04——悬浮导航栏中,我们把导航栏悬浮了起来。可是有时这个导航栏会挡住页面的一些内容,这时候我们就会想到要不要在某些条件下,让导航栏显示/隐藏起来?那办法肯定是有的,请看下面的预览效果。

预览效果

二、正题

本文中的悬浮导航栏我们的方案是当页面向上滑动时,让导航栏隐藏,向下滑动时让导航栏显示,该代码在项目路径:src/main/ets/pages/5-HiddenTabbar.ets

1、核心组件

系统库组件:

  • Tabs

2、核心代码

2.1 添加显隐变量

首先要有记录这个状态的变量,因为是上下两个方向,所以只需要用boolean值就行。默认为false,也就是不隐藏。

@State isHide: boolean = false;

2.2 页面操作

在首页的内容页面我们添加了List组件,它默认是可以滚动的,而且它的属性onScrollIndex()里面的参数就可以很好的让我们判断滑动方向。总共三个number类型参数:start、end和center,从字母意思就知道它们代表的什么意思。当前我们只需要用到start参数,如果以后大家碰到复杂的操作,可以适量使用三个参数来判断。

.onScrollIndex((firstIndex) => {
  if (firstIndex > this.lastFirstIndex) {
    this.isHide = true
  } else if (firstIndex < this.lastFirstIndex) {
    this.isHide = false
  }
  this.lastFirstIndex = firstIndex
})

三、完整代码

import { promptAction } from '@kit.ArkUI';

export class TabBarDataType {
  id: number;
  title: ResourceStr;
  selectedIcon: ResourceStr;
  defaultIcon: ResourceStr;

  constructor(id: number, title: ResourceStr, selectedIcon: ResourceStr, defaultIcon: ResourceStr) {
    this.id = id;
    this.title = title;
    this.selectedIcon = selectedIcon;
    this.defaultIcon = defaultIcon;
  }
}

const PUBLISH_TAB_BAR_INDEX: number = 1; // 初始化社区的tab下标

const TABINFO: TabBarDataType[] = [
  new TabBarDataType(0, '首页', $r("app.media.ic_tabbar_home_on"), $r("app.media.ic_tabbar_home_off")),
  new TabBarDataType(1, '发布', $r("app.media.ic_tabbar_publish_on"), $r("app.media.ic_tabbar_publish_off")),
  new TabBarDataType(2, '我的', $r("app.media.ic_tabbar_my_on"), $r("app.media.ic_tabbar_my_off")),
];

@Entry
@Component
export struct HiddenTabbar {
  @State isHide: boolean = false;
  @Provide selectedIndex: number = 0; // 初始化被选定的tabBar下标
  private controller: TabsController = new TabsController(); // 初始化Tab控制器
  private arr: number[] = new Array(20).fill(0); // 生成20个0的数组
  @State lastFirstIndex: number = 0

  build() {
    Stack({ alignContent: Alignment.Bottom }) {
      Tabs({ index: this.selectedIndex, barPosition: BarPosition.End, controller: this.controller }) {
        TabContent() {
          List({ space: 20 }) {
            ForEach(this.arr, (item: number, index: number) => {
              ListItem() {
                Text('向上滑动')
                  .fontSize(30)
              }
            })
          }
          .width('100%')
          .height('100%')
          .backgroundColor('#00CB87')
          .alignListItem(ListItemAlign.Center)
          .onScrollIndex((firstIndex) => {
            if (firstIndex > this.lastFirstIndex) {
              this.isHide = true
            } else if (firstIndex < this.lastFirstIndex) {
              this.isHide = false
            }
            this.lastFirstIndex = firstIndex
          })
        }

        TabContent() {
          // 占个位置而已
        }

        TabContent() {
          Column() {
            Text('我的内容')
              .fontSize(30)
          }
          .width('100%')
          .height('100%')
          .backgroundColor('#E67C92')
          .justifyContent(FlexAlign.Center)
        }
      }
      .barHeight(0)
      .vertical(false)
      .scrollable(false)
      .layoutWeight(1)
      .onChange((index: number) => {
        this.selectedIndex = index;
      })

      // 自定义TabBar组件
      CustomTabBar({ selectedIndex: $selectedIndex })
        .margin({ left: 20, right: 20 })
        .borderRadius(20)
        .offset({ y: -10 })
        .backgroundColor($r('app.color.tab_bar_background'))
        .visibility(this.isHide ? Visibility.Hidden : Visibility.Visible)
        .animation({
          duration: 300,
          curve: Curve.Ease,
          iterations: 1,
          playMode: PlayMode.Normal
        })
    }
    .width('100%')
    .height('100%')
    .borderRadius(8)

    // .backgroundColor(Color.Pink)
  }
}

@Component
struct CustomTabBar {
  @Link selectedIndex: number; // 初始化被选定的tabBar下标
  @State iconOffset: number = 0; // 初始化tabBar图片的偏移量

  aboutToAppear(): void {
    this.iconOffset = -3 // 应用启动后,给被选中的按钮抬升3vp
  }

  build() {
    Flex({ direction: FlexDirection.Row, justifyContent: FlexAlign.SpaceAround, alignItems: ItemAlign.Center }) {
      ForEach(TABINFO, (item: TabBarDataType, tabIndex: number) => {
        TabItem({
          iconOffset: this.iconOffset,
          tabBarIndex: tabIndex,
          selectedIndex: $selectedIndex,
        })
      })
    }
  }
}

@Component
struct TabItem {
  @Prop iconOffset: number; // 初始化tabBar图片的偏移量
  @Prop tabBarIndex: number; // tabBar下标
  @Link selectedIndex: number; // 初始化被选定的tabBar下标

  build() {
    Column() {
      Stack() {
        // 判断tab的下标是否不为1
        if (this.tabBarIndex !== PUBLISH_TAB_BAR_INDEX) {
          Column() {
            // 通过被选中的tabBar下标值和tabBar的默认下标值来改变图片显示
            Image(this.selectedIndex === this.tabBarIndex ? TABINFO[this.tabBarIndex].selectedIcon :
            TABINFO[this.tabBarIndex].defaultIcon)
              .width(28)
              .height(28)
              .interpolation(ImageInterpolation.High)
              .offset({
                y: (this.selectedIndex === this.tabBarIndex && this.selectedIndex !== PUBLISH_TAB_BAR_INDEX) ?
                this.iconOffset : 0
              })
              .animation({
                duration: 400,
                curve: Curve.Ease,
                iterations: 1,
                playMode: PlayMode.Normal
              })
          }
          .width(37)
          .height(37)
          .justifyContent(FlexAlign.Center)
        } else {
          Column() {
            Image(this.selectedIndex === this.tabBarIndex ? TABINFO[this.tabBarIndex].selectedIcon :
            TABINFO[this.tabBarIndex].defaultIcon)
              .width(60)
              .aspectRatio(1)
              .margin({ top: 4 })
              .interpolation(ImageInterpolation.High)
          }
          .width(80)
          .height(80)
          .borderRadius(40)
          .margin({ top: -10 })
          .backgroundColor($r('app.color.tab_bar_background'))
        }
      }

      if (this.tabBarIndex !== PUBLISH_TAB_BAR_INDEX) {
        Text(TABINFO[this.tabBarIndex].title)
          .fontSize(14)
          .fontColor(this.selectedIndex === this.tabBarIndex ? '#1296db' : '#707070')
      }
    }
    .width(60)
    .onClick(() => {
      if (this.tabBarIndex === PUBLISH_TAB_BAR_INDEX) {
        promptAction.showToast({
          message: '这里随你所愿',
          duration: 2000
        });
      } else {
        this.iconOffset = -3;
        this.selectedIndex = this.tabBarIndex;
      }
    })
  }
}

代码路径:https://gitcode.com/RybinWu/DiverseTabbar

Logo

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

更多推荐