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 { STYLE_CONFIGURATION } from '../model/constantsData';
import { promptAction } from '@kit.ArkUI';

const MAX_SHEET_COUNT = 6; // 最大页签数量
const HIDE_CLOSE_SHEET_COUNT = 4; // 隐藏关闭按钮时页签数量

@Component
export struct TabSheets {
  @Link tabArray: Array<number>; // 控制页签渲染的数组
  @Link @Watch('onFocusIndexChange') focusIndex: number; // Tabs组件当前显示的页签下标
  controller: TabsController = new TabsController(); // Tabs控制器
  @State middleIndex: number = this.focusIndex; // 中间变量
  private toastDuration: number = 2000; // toast弹窗时长

  /**
   * 更新中间变量
   */
  onFocusIndexChange() {
    this.middleIndex = this.focusIndex;
  }

  build() {
    Row({ space: STYLE_CONFIGURATION.TAB_BAR_ITEM_GUTTER }) {
      // 性能知识点:此处为横向列表,列表项确定且数量较少,使用了ForEach,在列表项多的情况下,推荐使用LazyForeEach
      ForEach(this.tabArray, (item: number, index: number) => {
        Row({ space: STYLE_CONFIGURATION.TAB_BAR_CONTENT_GUTTER }) {
          Image($r('app.media.handle_tabs_ic_public_worldclock_filled'))
            .width(STYLE_CONFIGURATION.ICON_SIZE)
            .aspectRatio(1)
          Text($r('app.string.handletabs_handle_tabs_new_sheet'))
            .textOverflow({ overflow: TextOverflow.Clip })
            .maxLines(1)
            .flexShrink(1)
          /**
           * 场景1:页签数量小于HIDE_CLOSE_SHEET_COUNT时,所有页签都显示关闭图标。
           * 场景2:页签数量大于HIDE_CLOSE_SHEET_COUNT时,只有获焦页签显示关闭图标。
           */
          Stack() {
            if (this.tabArray.length < HIDE_CLOSE_SHEET_COUNT || this.middleIndex === index) {
              Image($r('app.media.handle_tabs_ic_public_cancel_filled'))
                .id('tabs_cancel')
                .width(STYLE_CONFIGURATION.BIG_ICON_SIZE)
                .aspectRatio(1)
                .padding(STYLE_CONFIGURATION.BIG_ICON_PADDING)
                .margin(this.tabArray.length === MAX_SHEET_COUNT ? { right: STYLE_CONFIGURATION.IMAGE_MARGIN } : 0)
                .onClick(() => {
                  // 关闭页签
                  if (this.tabArray.length > 1) {
                    this.tabArray.splice(index, 1);
                    if (this.tabArray[index] === undefined) {
                      this.focusIndex = index - 1;
                    } else if (this.tabArray[index] !== undefined && this.focusIndex !== index) {
                      this.focusIndex -= 1;
                    }
                  }
                })
            }
          }
        }
        .flexShrink(1)
        .padding({
          left: $r('sys.float.ohos_id_elements_margin_horizontal_m'),
          right: $r('sys.float.ohos_id_elements_margin_horizontal_m')
        })
        .borderRadius($r('sys.float.ohos_id_corner_radius_default_xs'))
        .height('100%')
        .backgroundColor(this.middleIndex === index ? $r('sys.color.ohos_id_color_background') :
        $r('sys.color.ohos_id_color_sub_background'))
        .onClick(() => {
          this.controller.changeIndex(index);
          this.focusIndex = index;
        })

        // 性能知识点:if条件变更时,会导致if嵌套子组件所在的父组件接节点刷新,使用Stack容器可以减少刷新范围
        Stack() {
          if (this.middleIndex !== index && this.middleIndex - 1 !== index) {
            Divider()
              .vertical(true)
              .strokeWidth(STYLE_CONFIGURATION.SEPARATOR_STROKE_WIDTH)
              .height('50%')
              .lineCap(LineCapStyle.Round)
          }
        }
      })

      Image($r('app.media.handle_tabs_ic_public_add_filled'))
        .id('tabs_filled')
        .width(STYLE_CONFIGURATION.BIG_ICON_SIZE)
        .aspectRatio(1)
        .padding(STYLE_CONFIGURATION.BIG_ICON_PADDING)
        .onClick(() => {
          // 新增页签
          if (this.tabArray.length < MAX_SHEET_COUNT) {
            this.tabArray.push(this.tabArray.length);
            const newTabIndex: number = this.tabArray.length - 1;
            this.middleIndex = newTabIndex;
            animateTo({ duration: 200 }, () => {
              this.focusIndex = newTabIndex;
            })
          } else {
            promptAction.showToast({
              message: $r("app.string.handletabs_handle_toast"),
              duration: this.toastDuration
            });
          }
        })
    }
    .padding(STYLE_CONFIGURATION.TAB_SHEET_PADDING)
    .backgroundColor($r('sys.color.ohos_id_color_sub_background'))
    .width('100%')
    .height(STYLE_CONFIGURATION.TAB_BAR_HEIGHT)
  }
}