BottomNavigationComponent.ets 8.25 KB
import { BottomNavi, CommonConstants } from 'wdConstant';
import { BottomNavDTO, TopNavDTO } from 'wdBean';
import { DateTimeUtils, EmitterEventId, EmitterUtils, Logger } from 'wdKit';
import { TopNavigationComponent } from './TopNavigationComponent';
import { MinePageComponent } from './MinePageComponent';
import { CompUtils } from '../../utils/CompUtils';
import PageViewModel from '../../viewmodel/PageViewModel';
import HomeChannelUtils, { AssignChannelParam } from 'wdRouter/src/main/ets/utils/HomeChannelUtils';
import { Message } from 'wdJsBridge/src/main/ets/bean/Message';
import { VideoChannelPage } from './VideoChannelPage';

const TAG = 'BottomNavigationComponent';
let storage = LocalStorage.getShared();

/**
 * 底部页签导航栏/底导
 */
@Entry(storage)
@Component
export struct BottomNavigationComponent {
  @Provide bottomRectHeight: number = 0
  @Provide topRectHeight: number = 0
  @Provide isLayoutFullScreen: boolean = false
  @Provide isImmersive: boolean = false // 是否开启沉浸式模式 http://192.168.1.3:3300/project/3802/interface/api/189229
  @Provide isNight: boolean = false // 是否开启夜间模式
  @Provide currentBottomNavInfo: BottomNavDTO = {} as BottomNavDTO; // 当前底导信息
  @Provide currentTopNavInfo: TopNavDTO = {} as TopNavDTO; // 当前顶导信息
  @Provide barBackgroundColor: Color = Color.Transparent
  @State bottomSafeHeight: number = AppStorage.get<number>('bottomSafeHeight') || 0
  @State topSafeHeight: number = AppStorage.get<number>('topSafeHeight') || 0
  @State @Watch('onBottomNavigationDataUpdated') bottomNavList: BottomNavDTO[] = [] // 底导/顶导全部数据
  @State currentNavIndex: number = BottomNavi.NEWS; // 底导当前选中/焦点下标
  @State topNavList: TopNavDTO[] = []
  // 底导TabsController
  private navController: TabsController = new TabsController();
  readonly ASPECT_RATIO_1_1: number = 1 / 1; // 底导图片宽高比
  /**
   * Component opacity value: 1.
   */
  readonly FULL_OPACITY: number = 1;
  /**
   * Component opacity value: 0.6.
   */
  readonly SIXTY_OPACITY: number = 0.6;
  // 用于传参到顶导组件,【不用channelParam,主要是时序问题,需要先底导处理完,再延时触发顶导处理】
  @State assignChannel: AssignChannelParam = new AssignChannelParam()
  // 自动刷新触发(双击tab自动刷新)
  @State autoRefresh: number = 0

  async aboutToAppear() {
    Logger.info(TAG, `aboutToAppear currentNavIndex: ${this.currentNavIndex}`);
    let bottomNav = await PageViewModel.getBottomNavData(getContext(this))
    if (bottomNav && bottomNav.bottomNavList != null) {
      Logger.info(TAG, `aboutToAppear, bottomNav.length: ${bottomNav.bottomNavList.length}`);
      // 使用filter方法移除name为'服务'的项
      bottomNav.bottomNavList = bottomNav.bottomNavList.filter(item => item.name !== '服务');
      this.bottomNavList = bottomNav.bottomNavList
    }
    this.getTopNavList(this.bottomNavList[0]?.id)
    HomeChannelUtils.setBottomNavData(bottomNav)

    EmitterUtils.receiveEvent(EmitterEventId.JUMP_HOME_CHANNEL, (str?: string) => {
      Logger.debug(TAG, 'receiveEvent JUMP_HOME_CHANNEL: ' + str)
      if (str) {
        // 跳转指定频道场景,传参底导id、频道id
        let assignChannel = JSON.parse(str) as AssignChannelParam
        this.changeBottomNav(assignChannel)
      }
    })
  }

  aboutToDisappear() {
    Logger.info(TAG, `aboutToDisappear, this.currentNavIndex: ${this.currentNavIndex}`);
  }

  build() {
    Tabs({ barPosition: BarPosition.End, index: this.currentNavIndex, controller: this.navController }) {
      ForEach(this.bottomNavList, (navItem: BottomNavDTO, index: number) => {
        TabContent() {
          Column() {
            if (CompUtils.isMine(navItem)) {
              // 我的页面组件数据列表
              MinePageComponent()
            } else if (navItem.name === '视频') {
              // 视频频道,包含视频和直播
              VideoChannelPage({
                topNavList: navItem.topNavChannelList.filter(item => item.channelId != 2073),
                _currentNavIndex: $currentNavIndex,
              })
            } else {
              TopNavigationComponent({
                groupId: navItem.id,
                topNavList: navItem.topNavChannelList.filter(item => item.channelId != 2073),
                _currentNavIndex: $currentNavIndex,
                navIndex: index,
                currentBottomNavName: navItem.name,
                assignChannel: this.assignChannel,
                autoRefresh: this.autoRefresh
              })
            }

          }
        }
        .tabBar(this.tabBarBuilder(navItem, index))
        .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM])
      });

    }
    .scrollable(false)
    .animationDuration(0)
    .barHeight($r('app.float.bottom_navigation_barHeight'))
    .barMode(BarMode.Fixed)
    .barBackgroundColor(this.barBackgroundColor)
    // 备注:鸿蒙目前只有修改三线导航背景方法,对于全面屏导航条手机需要设置背景色并使其扩散到导航区域
    .backgroundColor(this.barBackgroundColor)
    .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM])

    // .padding({ bottom: this.bottomRectHeight + 'px', top: this.topRectHeight + 'px' }) // 此处margin具体数值在实际中应与导航条区域高度保持一致

  }

  @Builder
  tabBarBuilder(navItem: BottomNavDTO, index: number) {
    Stack({ alignContent: Alignment.Bottom }) {
      Image(this.currentNavIndex === index ? navItem.iconC : navItem.icon)
        .height(CommonConstants.FULL_PARENT)
        .padding({
          bottom: 15,
          left: 10,
          right: 10,
          top: 2
        })
        .aspectRatio(this.ASPECT_RATIO_1_1)

      Text(navItem.name)
        .margin({ bottom: $r('app.float.bottom_navigation_margin_bottom') })
        .fontWeight(this.currentNavIndex === index ? FontWeight.Bold : FontWeight.Normal)
        .textAlign(TextAlign.Center)
        .fontSize($r('app.float.font_size_10'))// .fontColor(this.currentNavIndex === index ? Color.Red : Color.Gray)
        .fontColor(this.currentNavIndex === index ? navItem.nameCColor : navItem.nameColor)
        .opacity(this.currentNavIndex === index ? this.FULL_OPACITY : this.SIXTY_OPACITY)
    }
    .height($r('app.float.bottom_navigation_barHeight'))
    .hoverEffect(HoverEffect.Highlight)
    .onClick(() => {
      Logger.info(TAG, `onChange, index: ${index}`);
      this.onBottomNavigationIndexChange(navItem, index)
    })

  }

  // 底导切换函数
  async onBottomNavigationIndexChange(navItem: BottomNavDTO, index: number) {
    Logger.info(TAG, `onBottomNavigationIndexChange this.currentNavIndex: ${this.currentNavIndex}`);
    if (navItem.name === '我的') {
      this.barBackgroundColor = Color.White
      this.currentBottomNavInfo = {} as BottomNavDTO
    } else {
      if (this.currentNavIndex === index) {
        // 当前tab,单击事件
        this.autoRefresh++
      } else {
        // 切换tab
        this.currentBottomNavInfo = navItem
      }
    }
    this.currentNavIndex = index;

    // 请求顶导数据(参数):
  }

  //请求顶导数据
  async getTopNavList(id: number) {
    let bottomNavDetail = await PageViewModel.getBottomNavDetailData(id)
    this.topNavList = bottomNavDetail?.topNavChannelList || []
  }

  onBottomNavigationDataUpdated() {
    // Logger.info(TAG, `onBottomNavigationDataUpdated currentNavIndex: ${this.currentNavIndex},length:${this.bottomNavItemList.length}`);
  }

  /**
   * 底导id变化,即指定频道跳转场景
   */
  changeBottomNav(assignChannel: AssignChannelParam) {
    let index = -1
    for (let i = 0; i < this.bottomNavList.length; i++) {
      let bottomNavDTO: BottomNavDTO = this.bottomNavList[i]
      if (bottomNavDTO.id.toString() === assignChannel.bottomNavId) {
        index = i
        break
      }
    }
    if (index >= 0 && index != this.currentNavIndex) {
      // 切底导
      this.currentNavIndex = index
    }

    setTimeout(() => {
      // 底导切换后,触发顶导切换
      this.assignChannel = new AssignChannelParam()
      this.assignChannel.pageId = assignChannel.pageId
      this.assignChannel.channelId = assignChannel.channelId
      this.assignChannel.bottomNavId = assignChannel.bottomNavId
    }, 20)
  }
}