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 { GroupAvatarModel, PersonData } from '../datasource/GroupAvatarModel';
import { SnapShotModel } from '../model/SnapShotModel';
import { image } from '@kit.ImageKit';

/**
 * 功能描述:点击完成之后,将选定的用户头像进行拼接,最终合成一个图片进行渲染。
 *
 * 实现原理:
 *   绘制组件
 *    1)使用divideImage2Group函数分割选择的用户头像数据,生成二维数组,已达到群头像排列方式,并设置图片宽高
 *    2)结合二位数组,嵌套2层ForEach组件实现纵向与横向的线性布局,绘制群头像
 *    3)设置id与visibility属性,用于隐藏组件及后续的组件截图
 *
 * @param {PersonData} imageArr - 已选择的联系人头像
 * @param {SnapShotModel | null} snapShotModel - 组件截图属性类
 */
@Component
export struct ImageCombination {
  // ---------------对外暴露变量-----------------
  // 已选择的联系人头像
  imageArr: (ResourceStr | image.PixelMap)[] = [];
  // 组件截图属性类
  snapShotModel: SnapShotModel | null = null;

  aboutToAppear(): void {
    if (!this.snapShotModel) {
      this.snapShotModel = new SnapShotModel();
    }
  }

  build() {
    // 绘制组件,用于绘制群组头像
    Column({ space: 2 }) {
      ForEach(divideImage2Group(this.imageArr), (item: GroupAvatarModel[]) => {
        RowComponent(item)
      })
    }
    // 设置组件ID,用于进行组件截图
    .id(this.snapShotModel?.getComponentId())
    .width($r('app.integer.group_avatar_custom_loading_drawing_size'))
    .height($r('app.integer.group_avatar_custom_loading_drawing_size'))
    .justifyContent(FlexAlign.Center)
    // 设置组件隐藏
    .visibility(Visibility.Hidden)
  }
}

/**
 * 群组头像横向列表组件
 * @param imageArray
 */
@Builder
function RowComponent(imageArray: GroupAvatarModel[]) {
  Row({ space: 2 }) {
    ForEach(imageArray, (item: GroupAvatarModel) => {
      Image(item.src)
        .height(item.height)
        .width(item.width)
    })
  }
  .width($r('app.integer.group_avatar_custom_loading_drawing_size'))
  .justifyContent(FlexAlign.Center)
}

/**
 * 将选择的头像列表组装为二位数组,用于填充九宫格组件
 * @param images
 * @returns
 */
function divideImage2Group(personGroup: (ResourceStr | image.PixelMap)[]): GroupAvatarModel[][] {
  let imageGroup: GroupAvatarModel[][] = [];
  if (personGroup.length <= 4) {
    // 人数少于等于4时,显示两行两列
    imageGroup = divideGroupBySize(personGroup, 2);
  } else if (personGroup.length <= 9) {
    // 人数大于4时,显示三行三列
    imageGroup = divideGroupBySize(personGroup, 3);
  } else {
    // 人数大于9时,仅显示前9个头像
    imageGroup = divideGroupBySize(personGroup.slice(0, 9), 3);
  }
  return imageGroup;
}

/**
 * 根据群组数量判断排列方式
 *  当群成员人数大于4人,则成员头像为整体区域的1/3,按照九宫格排列
 *  当群成员人数小于等于5人,则成员头像为整体区域的1/2,按照四宫格排列
 * @param images
 * @param rowSize
 * @returns
 */
function divideGroupBySize(personData: (ResourceStr | image.PixelMap)[], rowSize: number): GroupAvatarModel[][] {
  const imageCount: number = personData.length;
  const imageGroup: GroupAvatarModel[][] = [];
  let imageWidth: number = 0;
  let imageHeight: number = 0;
  let rowCount: number = 0;
  let firstRowCount: number = 0;

  // 设置群成员头像大小与排列方式
  if (rowSize === 2) {
    imageWidth = 30;
    imageHeight = 30;
    rowCount = Math.floor(imageCount / 2);
    firstRowCount = imageCount % 2;
  } else if (rowSize === 3) {
    imageWidth = 20;
    imageHeight = 20;
    rowCount = Math.floor(imageCount / 3);
    firstRowCount = imageCount % 3;
  }

  // 组装第一组图片数据
  const firstRowGroup: GroupAvatarModel[] = [];
  for (let i = 0; i < firstRowCount; i++) {
    firstRowGroup.push({
      src: personData[i],
      width: imageWidth,
      height: imageHeight
    });
  }
  // 当取余为0时,不需要单独设置首行组件
  if (firstRowGroup.length > 0) {
    imageGroup.push(firstRowGroup);
  }

  // 根据排列方式与非首行数,组装剩余的图片数据
  for (let i = 0; i < rowCount; i++) {
    const fullRowImages: (ResourceStr | image.PixelMap)[] =
      personData.slice(firstRowCount + i * rowSize, firstRowCount + (i + 1) * rowSize);
    const fullRowGroup: GroupAvatarModel[] = [];
    fullRowImages.forEach((img:ResourceStr | image.PixelMap) => {
      fullRowGroup.push({
        src: img,
        width: imageWidth,
        height: imageHeight
      });
    });
    imageGroup.push(fullRowGroup);
  }
  return imageGroup;
}