🎯 案例集合Tabs:自定义tabs突出(凸出)显示,异构,出血

🌍 案例集合Tabs

🏷️ 效果图

📖 参考

🧩 拆解

import { common } from "@kit.AbilityKit"
import { window } from "@kit.ArkUI"

interface AvoidArea {
  topRectHeight: number
  bottomRectHeight: number
}

// 1、定义相关关键字和接口
const statusBarType = window.AvoidAreaType.TYPE_SYSTEM
const navBarType = window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR

@Component
export struct tabHighlightedCase {
  private mockData: string[] = ['购物', '体育', '服装', '军事']
  private controller: TabsController = new TabsController()
  @State selectIdx: number = 0
  @State animationStartIdx: number = 0
  // 2、初始化状态
  context = this.getUIContext()?.getHostContext() as common.UIAbilityContext
  private windowClass = this.context.windowStage.getMainWindowSync()
  @State avoidArea: AvoidArea = { topRectHeight: 0, bottomRectHeight: 0 }

  // 4、生命周期中调用
  aboutToAppear(): void {
    this.windowClass.setWindowLayoutFullScreen(true)
    this.windowClass.on('avoidAreaChange', this.onAvoidAreaChange)
    this.setAvoidArea()
  }

  aboutToDisappear(): void {
    this.windowClass.setWindowLayoutFullScreen(false)
    this.windowClass.off('avoidAreaChange', this.onAvoidAreaChange)
  }

  // 3、设置状态栏和导航栏避让区域 && 监听不同设备避让区域的变化
  setAvoidArea() {
    const statusBarArea = this.windowClass.getWindowAvoidArea(statusBarType)
    this.avoidArea.topRectHeight = statusBarArea.topRect.height
    const navBarArea = this.windowClass.getWindowAvoidArea(navBarType)
    this.avoidArea.bottomRectHeight = navBarArea.bottomRect.height
  }

  onAvoidAreaChange = (data: window.AvoidAreaOptions) => {
    if (data.type === statusBarType) {
      this.avoidArea.topRectHeight = data.area.topRect.height
    } else if (data.type === navBarType) {
      this.avoidArea.bottomRectHeight = data.area.bottomRect.height
    }
  }

  @Builder
  tabBuilder(label: string, idx: number) {
    if (idx === 2) {
      Text().width(70)
    }

    Column({ space: 5 }) {
      Text(label)
        .fontSize(16)
        .fontColor(this.animationStartIdx === idx ? Color.White : Color.Black)
        .fontWeight(this.animationStartIdx === idx ? FontWeight.Medium : FontWeight.Normal)

      Image($r('app.media.startIcon'))
        .syncLoad(true)
        .draggable(false)
        .width(20)
        .height(20)
    }
    .onClick(() => {
      this.controller.changeIndex(idx)
      this.selectIdx = this.animationStartIdx = idx
    })
    .layoutWeight(1)
  }

  build() {
    Stack({ alignContent: Alignment.Bottom }) {
      Tabs({ index: this.selectIdx }) {
        ForEach(this.mockData, (item: string) => {
          TabContent() {
            Column() {
              Text(item)
                .fontColor(Color.White)
                .fontSize(20)
                .fontWeight(FontWeight.Bold)
            }
            .width('100%')
            .height('100%')
            .justifyContent(FlexAlign.Center)
            .backgroundColor(Color.Brown)
          }
        })
      }
      .barHeight(0)
      .onChange((idx: number) => {
        this.selectIdx = idx
      })
      // 关键:切换动画开始时触发该回调:解决切换tabs延迟的问题
      .onAnimationStart((idx: number, targetIndex: number) => {
        if (idx === targetIndex) {
          return
        }
        this.animationStartIdx = targetIndex
      })

      // 自定义tabs
      Row() {
        ForEach(this.mockData, (item: string, idx: number) => {
          this.tabBuilder(item, idx)
        })

        Text('+')
          .width(70)
          .aspectRatio(1)
          .fontSize(40)
          .fontColor(Color.White)
          .fontWeight(FontWeight.Regular)
          .textAlign(TextAlign.Center)
          .backgroundColor(Color.Blue)
          .borderRadius('50%')
          // 绝对定位
          //   将组件的左上角顶点定位到父容器水平方向的中心点(即X轴50%位置)。此时组件左侧与父容器中心线对齐,未实现视觉居中
          .position({ x: '50%', y: -20 })
          // 反向平移
          //   将组件沿X轴向左平移自身宽度的50%。通过负值偏移,组件的中心点移动到原定位点(父容器中心线),从而实现水平居中
          .translate({ x: '-50%' })
          .onClick(() => this.getUIContext().getPromptAction().showToast({ message: '添加独有逻辑' }))
      }
      .width('100%')
      .backgroundColor(Color.Gray)
      .padding({ bottom: this.avoidArea.bottomRectHeight + 'px', top: 5 })
    }
    .width('100%')
    .height('100%')
    .padding({ top: this.avoidArea.topRectHeight + 'px' })
  }
}

🌸🌼🌺

Logo

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

更多推荐