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 { TopTitle, ImageMapView, SettingItemView } from '../components/Component';
import { SettingItem } from '../utils/dataSource';
import { CommonConstants } from '../constants/CommonConstants';
import { BottomDrawer } from '../utils/BottomDrawer';
import { promptAction, window } from '@kit.ArkUI';
import { BottomDrawerHeight } from '../model/DataType';
import WindowModel from '../utils/WindowModel';
import { common } from '@kit.AbilityKit';
import { logger } from '../utils/Logger';
import { DynamicsRouter } from 'routermodule';
import { PlatformInfo, PlatformTypeEnum } from 'utils';

/**
 * 功能描述: 本示例主要介绍了利用List实现底部抽屉滑动效果场景,并将界面沉浸式(全屏)显示,及背景地图可拖动
 *
 * 推荐场景: 需要实现抽屉滑动效果的场景,如:打车页面、导航页面上拉显示更多内容等
 *
 * 核心组件:
 * 1. BottomDrawer-抽屉效果视图
 *
 * 实现步骤:
 * 1. 构建初始数据。
 * @example
 * const LIST_ITEM: SettingItem[] = [
         new SettingItem('list_item_id_first'),
         new SettingItem('list_item_id_second'),
         new SettingItem('list_item_id_third'),
         new SettingItem('list_item_id_fourth'),
         new SettingItem('list_item_id_fifth'),
         new SettingItem('list_item_id_sixth'),
         new SettingItem('list_item_id_seventh'),
         new SettingItem('list_item_id_eighth'),
 ];
 *
 * 2. 构建抽屉视图。其中listBuilder为列表模块,开发者可以自定义。
 * @example
 * BottomDrawer({
     searchAddress: this.searchAddress,
     listBuilder: this.listBuilder,
     isShow: this.isShow,
     bottomDrawerHeight: this.bottomDrawerHeight
   })
 *
 *
 */

// list内容项
const LIST_ITEM: SettingItem[] = [
  new SettingItem('list_item_id_first'),
  new SettingItem('list_item_id_second'),
  new SettingItem('list_item_id_third'),
  new SettingItem('list_item_id_fourth'),
  new SettingItem('list_item_id_fifth'),
  new SettingItem('list_item_id_sixth'),
  new SettingItem('list_item_id_seventh'),
  new SettingItem('list_item_id_eighth'),
];


@Component
export struct BottomDrawerSlideCase {
  @State isShow: boolean = false; // 顶部遮蔽导航栏区域是否显示
  @State bottomDrawerHeight: BottomDrawerHeight = new BottomDrawerHeight() // 抽屉组件阶段高度属性
  @State bottomHeight: number = 0; // 底部导航栏高度
  windowHeight: number = 0; // window高度
  statusBarHeight: number = 0; // 顶部状态栏高度
  private windowModel: WindowModel = WindowModel.getInstance(); // 窗口管理model

  build() {
    Stack({ alignContent: Alignment.TopStart }) {
      RelativeContainer() {
        // Image地图
        ImageMapView()
          .id('map')
        // list上部的标题栏
        this.itemHead('安全出行季')
        /**
         * 抽屉视图
         * @param { ()=>void } searchAddress - 搜索视图
         * @param {()=>void} listBuilder - 列表视图
         * @param { boolean } isShow - 控制标题栏是否显示
         * @param {BottomDrawerHeight} BottomDrawerHeight - 列表阶段高度属性
         */
        BottomDrawer({
          searchAddress: this.searchAddress,
          listBuilder: ()=>{
            this.listBuilder();
          },
          isShow: this.isShow,
          bottomDrawerHeight: this.bottomDrawerHeight
        })
      }

      /**
       * 顶部标题
       * @param {boolean} isShow - 顶部遮蔽导航栏区域是否显示
       */
      TopTitle({
        isShow: this.isShow
      })
        .id('title_bar')
    }.width(CommonConstants.FULL_SIZE)
    .height(CommonConstants.FULL_SIZE)
    .gesture(
      SwipeGesture({ direction: SwipeDirection.Horizontal })
        .onAction((event: GestureEvent) => {
          if (PlatformInfo.getPlatform() === PlatformTypeEnum.IOS) {
            if (event) {
              DynamicsRouter.popAppRouter();
            }
          }
        })
    )
  }

  // 搜索视图
  @Builder
  searchAddress() {
    Column() {
      Row() {
        Text($r("app.string.bottomdrawerslidecase_set_out"))
          .fontSize($r("app.integer.bottomdrawerslidecase_number_15"))
        Text($r("app.string.bottomdrawerslidecase_destination_new"))
          .fontSize($r("app.integer.bottomdrawerslidecase_number_15"))
          .fontColor(Color.Green)
        Text($r("app.string.bottomdrawerslidecase_get_on_the_car"))
          .fontSize($r("app.integer.bottomdrawerslidecase_number_15"))
      }
      .margin({ left: $r("app.integer.bottomdrawerslidecase_number_10") })
      .height($r("app.integer.bottomdrawerslidecase_height_50"))
      .width($r('app.string.bottom_drawer_slide_full_percent'))

      Text($r("app.string.bottomdrawerslidecase_please_destination"))
        .padding({ left: $r("app.integer.bottomdrawerslidecase_number_10") })
        .fontSize($r("app.integer.bottomdrawerslidecase_number_20"))
        .fontWeight(2)
        .height($r("app.integer.bottomdrawerslidecase_number_60"))
        .backgroundColor($r("app.color.bottomdrawerslidecase_list_first_backgroundcolor"))
        .borderRadius($r("app.integer.bottomdrawerslidecase_number_10"))
        .width($r('app.string.bottom_drawer_slide_full_percent'))
        .onClick(() => {
          promptAction.showToast({
            message: $r("app.string.bottomdrawerslidecase_promotion"),
            duration: 2000
          })
        })
    }
    .height(this.bottomDrawerHeight.minHeight)
    .width($r('app.string.bottom_drawer_slide_90_percent'))
    .padding({
      left: $r("app.integer.bottomdrawerslidecase_number_15"),
      right: $r("app.integer.bottomdrawerslidecase_number_15")
    })
    .justifyContent(FlexAlign.Center)
    .borderRadius($r("app.integer.bottomdrawerslidecase_number_10"))
    .shadow({
      radius: $r("app.integer.bottomdrawerslidecase_number_30"), // 阴影模糊半径
      color: $r("app.color.bottomdrawerslidecase_list_first_backgroundcolor"),
      offsetY: $r("app.integer.bottomdrawerslidecase_number_5") // Y轴偏移量
    })
  }

  // 列表视图
  @Builder
  listBuilder() {
    ForEach(LIST_ITEM, (item: SettingItem, index: number) => {
      ListItem() {
        SettingItemView()
      }
      .backgroundColor(Color.White)
      .width(CommonConstants.FULL_SIZE)
      .margin({
        bottom: index === LIST_ITEM.length - 1 ? this.bottomHeight : 0
      })
    }, (item: SettingItem) => item.id.toString())
  }

  // list上部的标题栏
  @Builder
  itemHead(text: string) {
    Column() {
      Row() {
        Text(text)
          .fontSize($r('app.string.bottomdrawerslidecase_fontsize_15'))
          .fontColor($r("app.color.bottomdrawerslidecase_list_header_text"))
      }
      .shadow({
        radius: $r("app.integer.bottomdrawerslidecase_number_10"), // 阴影模糊半径
        color: $r("app.color.bottomdrawerslidecase_list_header_shadow"),
      })
      .height($r("app.integer.bottomdrawerslidecase_height_50"))
      .width($r('app.string.bottom_drawer_slide_40_percent'))
      .margin({ left: $r("app.integer.bottomdrawerslidecase_number_30") })
      .backgroundColor($r("app.color.bottomdrawerslidecase_list_header_backgroundcolor"))
      .borderRadius($r("app.integer.bottomdrawerslidecase_number_10"))
      .padding({ left: $r("app.integer.bottomdrawerslidecase_number_15") })

      Blank()
        .height($r("app.integer.bottomdrawerslidecase_number_10"))
        .backgroundColor(Color.Transparent)
    }
    .id('listHeader')
    .alignRules({
      'bottom': { 'anchor': 'scrollPart', 'align': VerticalAlign.Top },
      'left': { 'anchor': '__container', 'align': HorizontalAlign.Start },
      'right': { 'anchor': '__container', 'align': HorizontalAlign.End },
    })
    .height(CommonConstants.LIST_HEADER_HEIGHT)
    .borderRadius($r("app.integer.bottomdrawerslidecase_number_10"))
  }

  aboutToAppear(): void {
    // 初始化窗口管理model
    let context = getContext() as common.UIAbilityContext;
    const windowStage: window.WindowStage | undefined =
      PlatformInfo.isArkUIX() ? AppStorage.get('windowStage') : context.windowStage;
    // 没有windowStage将无法执行下列逻辑
    if (!windowStage) {
      logger.warn('windowStage init error!');
      return;
    }
    this.windowModel.setWindowStage(windowStage);
    this.windowModel.getStatusBarHeight((statusBarHeight) => {
      this.statusBarHeight = px2vp(statusBarHeight);
    })
    this.windowModel.getBottomAvoidHeight((bottomHeight) => {
      this.bottomHeight = px2vp(bottomHeight);
    })
    if (PlatformInfo.isArkUIX()) {
      this.windowModel.getArkuiXWindowHeight((arkuiXWindowHeight) => {
        this.bottomDrawerHeight.maxHeight = px2vp(arkuiXWindowHeight) - CommonConstants.LIST_HEADER_HEIGHT;
      })
    } else {
      // 获取窗口高度
      this.windowModel.getWindowHeight().then(s => {
        this.windowHeight = s;
        this.bottomDrawerHeight.maxHeight = this.windowHeight - this.statusBarHeight - CommonConstants.LIST_HEADER_HEIGHT; // 设置list最大高度
      })
    }

  }
}