【入门到精通】鸿蒙next应用开发:群头像拼接实现案例

 往期鸿蒙5.0全套实战文章必看:(文中附带鸿蒙5.0全栈学习资料)


介绍

本示例介绍使用组件截图 实现组件的截图并获取pixelMap对象。该场景多用于通信类应用。

效果图预览

使用说明

  1. 进入群头像案例页面,点击右上角添加图标,在弹出的菜单中点击发起群聊,跳转至发起群聊页面。
  2. 发起群聊页面中,点击下方用户列表前的选择框,选中多个用户,点击右下方完成按钮,添加会话数据。
  3. 在案例首页可以查看新增的会话数据,并可根据选择的用户自行展示群头像。

下载安装

1.模块oh-package.json5文件中引入依赖。

"dependencies": {
  "@ohos-cases/groupavatar": "har包地址"
}

2.ets文件import自定义视图实现组件拼接。

import { ImageCombination, SnapShotModel } from '@ohos-cases/groupavatar';

快速使用

1.当前组件默认id为avatar_group,开发者也可以通过SnapShotModel的setComponentId函数来设置组件id值。

this.snapShotModel.setComponentId('id名称')

2.构建图片拼接组件视图。

ImageCombination({
  imageArr: this.imageArr,
  snapShotModel: this.snapShotModel
})

3.执行组件截图逻辑。

let imagePixelMap = this.snapShotModel?.getSnapShot();

属性(对外)接口

SnapShotModel - 组件截图类

属性类型释义默认值
setComponentId(componentId: string) => void设置id-
getSnapShot() => void获取组件截图-
getComponentId() => void获取组件Id-

ImageCombination - 组件拼接视图

属性类型释义默认值
imageArrResourceStr[]\image.PixelMap[]已选择的联系人头像-
snapShotModelSnapShotModel组件截图属性类-

实现思路

利用组件截图能力获取群头像绘制组件图像。当组件的visibility属性不为None时,均可进行组件截图。

  1. 通过选择的数据,组装群头像布局组件数据。
/**
 * 将选择的头像列表组装为二维数组,用于填充九宫格组件
 * @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;
}
  1. 通过嵌套两层ForEach组件,实现纵向与横向的线性布局。
// 绘制组件,用于绘制群组头像
Column({ space: 2 }) {
  ForEach(divideImage2Group(this.imageArr), (item: GroupAvatarModel[]) => {
    RowComponent(item)
  })
}
// 设置组件ID,用于进行组件截图
.id(this.snapShotModel?.getComponentId())
.width(64)
.height(64)
.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(64)
  .justifyContent(FlexAlign.Center)
}
  1. 使用Stack组件与visibility属性控制组件不显示,设置id属性,用于后续的组件截图操作。
// 使用堆叠组件,实现绘制组件在loading动画后执行
Stack() {
  // 绘制组件,用于绘制群组头像
  Column({ space: 2 }) {
    ForEach(divideImage2Group(this.selectPersonGroup), (item: GroupAvatarModel[]) => {
      RowComponent(item)
    })
  }
  // 设置组件ID,用于进行组件截图
  .id('avatar_group')
  .visibility(Visibility.Hidden)

  // loading弹框
  Column() {
    ...
  }
}
  1. 使用@ohos.arkui.componentSnapshot接口实现组件截图,并获取群头像资源。
getSnapShot(scale: number = 1, waitUntilRenderFinished?: boolean): image.PixelMap {
  let snapshotOptions: componentSnapshot.SnapshotOptions = {
    scale,
    waitUntilRenderFinished
  }
  return componentSnapshot.getSync(this.componentId, snapshotOptions);
}

高性能知识点

不涉及

工程结构&模块类型

groupavatar                                     // har类型
|---datasource
|   |---DataSource.ets                          // 本地数据 
|   |---GroupAvatarModel.ets                    // 数据模型
|---model
|   |---SnapShotModel.ets                       // 图片截图类
|---utils
|   |---ImageCombination.ets                    // 图片拼接组件
|---view
|   |---components
|   |   |---BottomBarContent.ets                // 底部Tab组件
|   |   |---NavigationBarContent.ets            // 顶部导航栏
|   |   |---PersonContent.ets                   // 用户列表页面
|   |   |---SessionContent.ets                  // 会话列表页面
|   |---GroupAvatarAddPage.ets                  // 发起群聊页面
|   |---GroupAvatarAddPage.ets                  // 首页

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值