HarmonyOS Next如何实现居左对齐的顶部导航样式?

阅读 489
1 个回答
//Stack组件中嵌套Row组件和Column组件,实现导航条文字和下划线两部分
// entry/src/main/ets/pages/LeftTab.ets
Stack({ alignContent: Alignment.TopStart }) {
  // 导航条文字
  Row() {
    ForEach(this.tabArray, (item: number, index: number) => {
      this.tab('页签 ' + item, item, index);
    })
    Blank()
    Text('+')
      .width(24)
      .height(24)
      .fontSize(24)
      .textAlign(TextAlign.Center)
      .margin({ right: 24 })
  }
  .justifyContent(FlexAlign.Start)
  .width('100%')

  // 导航条下划线
  Column()
    .width(this.indicatorWidth)
    .height(1.5)
    .backgroundColor('#0A59F7')
    .borderRadius(1)
    .margin({ left: this.indicatorLeftMargin, top: 35 })
}
.height(56)
.margin({ left: this.tabLeftOffset })
//在onAreaChange()中计算当前激活Tab距离屏幕左侧的偏移量,赋值给indicatorLeftMargin变量,控制下划线的位置。
// entry/src/main/ets/pages/LeftTab.ets
@Builder
tab(tabName: string, _tabItem: number, tabIndex: number) {
  Row() {
    Text(tabName)
      .fontColor($r('sys.color.font_primary'))
      .lineHeight(22)
      .fontColor(tabIndex === this.currentIndex ? '#0A59F7' : '#E6000000')
      .id(tabIndex.toString())
      .onAreaChange((_, newValue: Area) => {
        if (this.currentIndex === tabIndex && (this.indicatorLeftMargin === 0 || this.indicatorWidth === 0)) {
          let positionX: number;
          let width: number = Number.parseFloat(newValue.width.toString());
          if (newValue.position.x !== undefined) {
            positionX = Number.parseFloat(newValue.position.x?.toString())
            this.indicatorLeftMargin = Number.isNaN(positionX) ? 0 : positionX;
          }
          this.indicatorWidth = width;
        }
      })
  }
  .justifyContent(FlexAlign.Center)
  .constraintSize({ minWidth: 35 })
  .width(64)
  .height(35)
  .onClick(() => {
    this.controller.changeIndex(tabIndex);
    this.currentIndex = tabIndex;
  })
}
//在点击页签过程中,实时计算选中页签距离左侧的偏移量和页签的宽度,并更新下划线的位置和宽度
// entry/src/main/ets/pages/LeftTab.ets
// 点击tab切换
.onAnimationStart((_index: number, targetIndex: number, _event: TabsAnimationEvent) => {
  this.currentIndex = targetIndex;
  let targetIndexInfo = this.getTextInfo(targetIndex);
  this.startAnimateTo(this.animationDuration, targetIndexInfo.left, targetIndexInfo.width);
})

private getTextInfo(index: number): Record<string, number> {
  let modePosition: componentUtils.ComponentInfo = componentUtils.getRectangleById(index.toString());
  return { 'left': px2vp(modePosition.windowOffset.x), 'width': px2vp(modePosition.size.width) };
}

private startAnimateTo(duration: number, leftMargin: number, width: number) {
  animateTo({
    duration: duration,
    curve: Curve.Linear,
    iterations: 1,
    playMode: PlayMode.Normal,
  }, () => {
    this.indicatorLeftMargin = leftMargin;
    this.indicatorWidth = width;
  })
}
//在左右滑动页面过程中,当滑动距离超出屏幕宽度一半时,更新下划线的位置和宽度。
// entry/src/main/ets/pages/LeftTab.ets
// 触摸滑动切换
.onGestureSwipe((index: number, event: TabsAnimationEvent) => {
  let currentIndicator = this.getCurrentIndicatorInfo(index, event);
  this.currentIndex = currentIndicator.index;
  this.indicatorLeftMargin = currentIndicator.left;
  this.indicatorWidth = currentIndicator.width;
})

private getCurrentIndicatorInfo(index: number, event: TabsAnimationEvent): Record<string, number> {
  let nextIndex = index;
  if (index > 0 && event.currentOffset > 0) {
    // 向左滑动切换
    nextIndex--;
  } else if (index < this.tabArray.length && event.currentOffset > 0) {
    // 向右滑动切换
    nextIndex++;
  }
  let indexInfo = this.getTextInfo(index);
  let nextIndexInfo = this.getTextInfo(index);

  let swipeRatio = Math.abs(event.currentOffset / this.tabsWidth);
  let currentIndex = swipeRatio > 0.5 ? nextIndex : index;
  let currentIndicatorLeft: number = indexInfo.left + (nextIndexInfo.left - indexInfo.left) * swipeRatio;
  let currentIndicatorWidth: number = indexInfo.width + (nextIndexInfo.width - indexInfo.width) * swipeRatio;
  return { 'index': currentIndex, 'left': currentIndicatorLeft, 'width': currentIndicatorWidth };
}

本文参与了 【 HarmonyOS NEXT 技术问答冲榜,等你来战!】欢迎正在阅读的你也加入。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进