一、前言

在上一讲的鸿蒙开发之多样化底部导航栏02——凸起导航栏中,我们的应用开始脱离标准的默认导航栏束缚。所以,为了用户感受到更加炫酷的细节,我们就需要加一些动效更加让用户被带入的感受。而且通过该章节,我们将会学习到过渡动画知识点。

预览效果

 

二、正题

本文中的灵动导航栏我们打算让按钮在点击之后,有向上和向下滑动效果,该代码在项目路径:src/main/ets/pages/3-DynamicTabbar.ets

1、核心组件

系统库组件:

  • Tabs

属性:

  • .animation()

2、核心代码

2.1 添加偏移量

在自定义的Tabbar组件中,添加默认的iconOffset偏移量,在启动应用时,给它一个默认的iconOffset = -3值,这样在默认选择【首页】页签中,就会呈现首页图标和文字上下距离抬高的效果,当我们点击【我的】按钮后,首页页签图标和文字有拉进距离的动效,我的页签按钮这会有向上排挤动效。

@Prop iconOffset: number; // 初始化tabBar图片的偏移量


Image()
 ...
 .offset({
  y: (...) ? this.iconOffset : 0
 })
 .animation({})

2.2 属性动画animation()

通过该属性动画的参数,就可以设置自己喜欢的样式。duration是动画时长,curve是动画曲线样式,iterations:是动画循环次数,这里只需要1次。playMode是动画播放模式,默认播放完成后重头开始播放。

animation({ // 属性动画
    duration: 400,
    curve: Curve.Ease,
    iterations: 1,
    playMode: PlayMode.Normal
  })

2.3 TabItem()

在点击按钮之后,设置偏移量为-3vp,表示向上抬起3vp

Column() {
   ...
}
...
.onClick(() => {
      if (this.tabBarIndex === PUBLISH_TAB_BAR_INDEX) {
        ...
      } else {
        this.iconOffset = -3; //在点击按钮之后,设置偏移量为-3vp,表示向上抬起3vp
      }
    })

三、完整代码

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 DynamicTabbar {
  @Provide selectedIndex: number = 0; // 初始化被选定的tabBar下标
  private controller: TabsController = new TabsController(); // 初始化Tab控制器

  build() {
    Column() {
      Tabs({ index: this.selectedIndex, barPosition: BarPosition.End, controller: this.controller }) {
        TabContent() {
          Column() {
            Text('首页的内容')
              .fontSize(30)
          }
          .width('100%')
          .height('100%')
          .backgroundColor('#00CB87')
          .justifyContent(FlexAlign.Center)
        }

        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 })
    }
    .width('100%')
    .height('100%')
  }
}

@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)
            // .backgroundColor(Color.Pink)
          }
          .width(80)
          .height(80)
          .borderRadius(40)
          .margin({ top: -10 })
          .backgroundColor(Color.White)
        }
      }

      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、测试、元服务和应用上架分发等。

更多推荐