9afce6f6创建于 2025年5月7日历史提交
/*
 * Copyright (c) 2024 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import util from '@ohos.util';
import { STYLE_CONFIGURATION } from '../model/constantsData';
import { MenuBar } from './MenuBar';
import { TabSheets } from './TabSheetComponent';

/**
 * 功能描述: 本示例介绍使用了Tab组件实现自定义增删Tab页签的功能。
 *
 * 推荐场景: 多用于浏览器等场景。
 *
 * 核心组件:
 * 1. 自定义TabBar
 *
 * 实现步骤:
 *  1. 设置Tab组件的barHeight为0,隐藏组件自带的TabBar。
 *  2. 使用@Link修饰符,将自定义TabBar组件和Tab组件通过focusIndex和tabArray进行双向绑定。
 *  3. 在自定义TabBar中修改focusIndex和tabArray的值时,Tab组件根据数据变化进行对应UI变更。
 */
@Component
export struct HandleTabsComponent {
  @State tabArray: Array<number> = [0]; // 控制页签渲染的数组
  @State focusIndex: number = 0; // Tabs组件当前显示的页签下标
  private addressList: Array<number> = new Array(8).fill(0) // 快捷方式集合
  controller: TabsController = new TabsController(); // Tabs控制器

  /**
   * TabContent内容视图
   */
  @Builder
  tabContentBuilder() {
    Column() {
      Search().width('90%')
      Grid() {
        // 性能知识点:此处列表项确定且数量较少,使用了ForEach,在列表项多的情况下,推荐使用LazyForeEach
        ForEach(this.addressList, () => {
          GridItem() {
            Column({ space: STYLE_CONFIGURATION.CONTENT_GUTTER_S }) {
              Text()
                .width(STYLE_CONFIGURATION.IMAGE_SIZE)
                .aspectRatio(1)
                .backgroundColor($r('app.color.handletabs_handle_tabs_third_black'))
                .borderRadius(STYLE_CONFIGURATION.IMAGE_RADIUS)
              Text()
                .width(STYLE_CONFIGURATION.TEXT_WIDTH)
                .height(STYLE_CONFIGURATION.TEXT_HEIGHT)
                .backgroundColor($r('app.color.handletabs_handle_tabs_third_black'))
            }
          }
          .id('add_tabs')
        })
      }
      .columnsTemplate('1fr 1fr 1fr 1fr')
      .rowsGap(STYLE_CONFIGURATION.CONTENT_GUTTER_M)
      .rowsTemplate('1fr 1fr')
      .height(STYLE_CONFIGURATION.GRID_HEIGHT)
      .margin({ top: STYLE_CONFIGURATION.GRID_MARGIN })
    }
    .height('100%')
    .justifyContent(FlexAlign.Center)
  }

  build() {
    Column() {
      /**
       * 自定义TabBar组件
       * TODO:知识点:1.隐藏系统Tab组件的TabBar,在自定义tabBar组件中,修改focusIndex实现不同页签切换
       */
      TabSheets({ tabArray: $tabArray, focusIndex: $focusIndex, controller: this.controller })

      // 工具栏
      MenuBar()

      Divider()
        .width('100%')
        .backgroundColor($r('sys.color.ohos_id_color_subheading_separator'))

      Tabs({ barPosition: BarPosition.Start, index: this.focusIndex, controller: this.controller }) {
        /**
         * TODO:知识点:2.通过ForEach循环数组动态创建TabContent组件
         * 性能知识点:ForEach的第三个入参keyGenerator唯一时,动态修改ForEach时,可降低渲染开销
         * 参考文档:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-rendering-control-foreach-0000001820999585
         */
        ForEach(this.tabArray, (item: number, index: number) => {
          TabContent() {
            Column() {
              if (this.tabArray[index] === 0) {
                FunctionDescription({
                  title: $r('app.string.handletabs_handle_tabs_handle_tabs'),
                  content: $r('app.string.handletabs_handle_tabs_handle_tabs_desc')
                })
              } else {
                this.tabContentBuilder()
              }
            }
            .height('100%')
          }
        }, (item: number) => item.toString() + util.generateRandomUUID())
      }
      .scrollable(false)
      .barHeight(0) // 隐藏tab组件自带的tabbar
      .onChange((index: number) => {
        this.focusIndex = index;
      })
    }.width("100%")
  }
}

/**
 * 模块功能描述组件
 * @param title 标题
 * @param context 内容
 */
@Component
struct FunctionDescription {
  private title: ResourceStr = '';
  private content: ResourceStr = '';

  build() {
    Column() {
      Row() {
        Text(this.title)
          .fontSize($r('app.string.handletabs_text_size_headline'))
          .fontWeight(FontWeight.Medium)
          .textOverflow({overflow:TextOverflow.Ellipsis})
          .maxLines(1)
      }
      .margin({ bottom: $r('app.string.handletabs_elements_margin_vertical_m') })
      Row(){
        Text(this.content)
          .wordBreak(WordBreak.BREAK_ALL)
      }
      .width('100%')
    }
    .width('100%')
    .backgroundColor($r('app.color.handletabs_color_sub_background'))
    .borderRadius($r('app.string.handletabs_corner_radius_default_m'))
    .padding($r('app.string.handletabs_card_padding_start'))
  }
}