HarmonyOS鸿蒙开发实战(5.0)表情图片聊天案例实践

news2024/11/16 13:47:15

鸿蒙HarmonyOS NEXT开发实战往期文章必看(持续更新......)

HarmonyOS NEXT应用开发性能实践总结

HarmonyOS NEXT应用开发案例实践总结合集

最新版!“非常详细的” 鸿蒙HarmonyOS Next应用开发学习路线!(从零基础入门到精通)

非常详细的” 鸿蒙HarmonyOS Next应用开发学习路线!


介绍

本示例主要介绍如何在聊天信息中加入表情图片。通过变量控制表情键盘的显示与否,使用RichEdit接收所选表情的ImageSpan。在发送信息时将图片和文字消息分别通过ImageSpan、Span加入到消息列表中,显示的时候将消息列表中的ImageSpan、Span包裹在Text中进行显示,同时实现了最近使用表情和长按表情图片弹窗显示表情明细的效果。

效果图预览

使用说明

  1. 进入页面,在底部输入框中输入文字,点击输入框右边的表情图片按钮弹出表情键盘,长按表情图片弹窗显示表情明细。在表情键盘中选择表情图片后点击发送,在聊天对话框中会显示聊天文字以及表情。

实现思路

  1. 将实现了Popup效果的单个表情功能封装成EmojiDetail自定义组件。选中表情图片后,将表情通过imageSpan的方式加到RichEditor输入框中,同时加入到最近使用的表情数据列表中。源码参考EmojiDetail.ets

    Image(this.EmojiItem!.imgSrc)
      .width(FaceGridConstants.EMOJI_IMAGE_SIZE)
      .height(FaceGridConstants.EMOJI_IMAGE_SIZE)
      .onClick(() => {
        // TODO 知识点:将表情添加到输入框中
        this.controllerRich!.addImageSpan(this.EmojiItem!.imgSrc, {
          imageStyle: {
            size: [this.msgFontSize / 3.2, this.msgFontSize / 3.2], // 3.2 调整表情在输入框中的尺寸
            verticalAlign: ImageSpanAlignment.CENTER
          }
        });
        // TODO 知识点:将表情添加到最近使用表情中
        this.lastEmojiData.pushData(this.EmojiItem!);
      })
      .draggable(false)
      .gesture(
        // TODO 知识点:长按弹出表情明细
        LongPressGesture()
          .onAction(() => {
            this.isPopup = true;
          })
          .onActionEnd(() => {
            this.isPopup = false;
          })
      )
      .bindPopup(this.isPopup, {
        // TODO 知识点:使用bindPopup弹出表情明细
        builder: this.popupBuilder, onStateChange: (e) => {
          if (!e.isVisible) {
            this.isPopup = false;
          }
        }
      })
    
  2. 使用Grid和EmojiDetail自定义组件创建表情键盘,源码参考EmojiKeyboard.ets

    Grid() {
      // TODO: 性能知识点:使用ForEach组件循环渲染数据
      ForEach(this.emojiList, (item: EmojiModel) => {
        GridItem() {
          // 表情明细组件
          EmojiDetail({
            controllerRich: this.controllerRich,
            EmojiItem: item,
            msgFontSize: this.msgFontSize,
            lastEmojiData: this.lastEmojiData
          })
        }
      })
    }
    .maxCount(FaceGridConstants.GRID_MAX_COUNT)
    .columnsTemplate("1fr 1fr 1fr 1fr 1fr 1fr") // 分成6份
    .rowsGap(FaceGridConstants.ROWS_GAP)
    
  3. 点击表情按钮时弹出最近表情和全部表情键盘,源码参考ChatWithExpression.ets

    // TODO 知识点:通过变量控制表情键盘的显示
    if (this.isFaceDlgOpen) {
      Column() {
        // 最近使用的表情
        if (this.lastEmojiData.totalCount() > 0) {
          Text($r('app.string.chat_with_expression_last_emoji')).alignSelf(ItemAlign.Start)
            .margin($r('app.integer.chat_with_expression_chat_margin_top'))
          // 表情键盘组件
          Emojikeyboard({
            controllerRich: this.controllerRich,
            msgFontSize: this.msgFontSize,
            lastEmojiData: this.lastEmojiData,
            emojiList: this.lastEmojiData.emojiList
          })
        }
        // 全部表情
        Text($r('app.string.chat_with_expression_all_emoji')).alignSelf(ItemAlign.Start)
          .margin($r('app.integer.chat_with_expression_chat_margin_top'))
        // 表情键盘组件
        Emojikeyboard({
          controllerRich: this.controllerRich,
          msgFontSize: this.msgFontSize,
          lastEmojiData: this.lastEmojiData,
          emojiList: EmojiData
        })
      }
    }
    
  4. 点击发送时,通过RichEditorController的getSpans方法,将聊天信息中ImageSpan、Span分别push到要发送的信息的spanItems中。源码参考ChatWithExpression.ets的sendChatMsg方法

    let msgBase = new MessageBase(true, USER_NAME_MYSELF, HEAD_IMAGE_MYSELF, this.msgMaxWidth);
    // 获取发送信息
    this.controllerRich.getSpans({
      start: this.start,
      end: this.end
    }).forEach(item => {
      if (typeof (item as RichEditorImageSpanResult)['imageStyle'] !== 'undefined') {
        // TODO 知识点:处理imagespan信息
        const imageMsg: ResourceStr | undefined = (item as RichEditorImageSpanResult).valueResourceStr;
        if (imageMsg !== undefined) {
          const spanItem: SpanItem = new SpanItem(SpanType.IMAGE, '', imageMsg.toString().substring(EMOJI_SRC_POS));
          msgBase.spanItems.push(spanItem);
        }
      } else {
        // TODO 知识点:处理文字span信息
        const textMsg: string = (item as RichEditorTextSpanResult).value;
        const spanItem: SpanItem = new SpanItem(SpanType.TEXT, textMsg, '');
        msgBase.spanItems.push(spanItem);
      }
    })
    logger.info(TAG, 'sendChatMsg spanItems:' + msgBase.spanItems.length.toString());
    // 发送
    if (msgBase.spanItems.length !== 0) {
      this.textDetailData.pushData(msgBase);
      this.msgNums = this.textDetailData.totalCount();
      this.scroller.scrollToIndex(this.msgNums - 1);
      this.controllerRich.deleteSpans();
      this.controllerRich.setCaretOffset(-1);
    }
    this.customFaceDialogCtl.close();
    this.isFaceDlgOpen = false;
    this.marginBottomInput = 0;
    focusControl.requestFocus(this.focusKey);
    
  5. 在聊天对话框中通过LazyForEach循环加载聊天信息。

    // 聊天对话框
    List({
      scroller: this.scroller,
      initialIndex: this.msgNums - 1
    }) {
      // 性能知识点:使用懒加载组件渲染数据。参考资料:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-rendering-control-lazyforeach-0000001820879609
      LazyForEach(this.textDetailData, (msg: MessageBase) => {
        ListItem() {
          if (msg.isSelf) {
            MessageItemSelfView({ msg: msg });
          } else {
            MessageItemView({ msg: msg });
          }
        }
      })
    }
    
  6. 将聊天信息的SpanItems根据spanType在Text中分别包裹为ImageSpan跟Span。

    // 聊天信息
    Row() {
      Text(undefined) {
        // TODO: 性能知识点:使用ForEach组件循环渲染数据
        ForEach(this.msg.spanItems, (item: SpanItem) => {
          // TODO 知识点:分别使用ImageSpan、Span渲染图片、文字信息
          if (item.spanType === SpanType.IMAGE) {
            ImageSpan($rawfile(item.imgSrc as string))
              .width($r('app.integer.chat_font_size'))
              .height($r('app.integer.chat_font_size'))
              .verticalAlign(ImageSpanAlignment.BOTTOM).objectFit(ImageFit.Cover)
          } else if (item.spanType === SpanType.TEXT) {
            Span(item.text)
          }
        })
      }.constraintSize({
        minHeight: $r('app.integer.chat_inline_height'),
        maxWidth: this.msg.maxWidth
      })
      .textAlign(TextAlign.Start)
    }
    

高性能知识点

本示例使用了LazyForEach进行数据懒加载,同时搭配组件复用能力以达到性能最优效果。

工程结构&模块类型

chatwithexpression                            // har类型
|---view
|   |---ChatWithExpression.ets               // 视图层-表情聊天界面
|---constants
|   |---ChatConstants.ets                    // 常量
|---model
|   |---Emoji.ets                            // 表情资源
|   |---Message.ets                          // 消息结构
|   |---BasicDataSource.ets                  // 数据类型文件

最后

小编在之前的鸿蒙系统扫盲中,有很多朋友给我留言,不同的角度的问了一些问题,我明显感觉到一点,那就是许多人参与鸿蒙开发,但是又不知道从哪里下手,因为体系杂乱无章,教授的人也多,无从选择。有很多小伙伴不知道学习哪些鸿蒙开发技术?不知道需要重点掌握哪些鸿蒙应用开发知识点?而且学习时频繁踩坑,最终浪费大量时间。所以有一份实用的鸿蒙(HarmonyOS NEXT)路线、视频、文档用来跟着学习是非常有必要的。

如果你是一名有经验的资深Android移动开发、Java开发、前端开发、对鸿蒙感兴趣以及转行人员

鸿蒙 NEXT 全栈开发学习笔记 希望这一份鸿蒙学习文档能够给大家带来帮助~

这份鸿蒙(HarmonyOS NEXT)包含了鸿蒙开发必掌握的核心知识要点,内容包含了(ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、(南向驱动、嵌入式等)鸿蒙项目实战等等)鸿蒙(HarmonyOS NEXT)技术知识点。


 鸿蒙(HarmonyOS NEXT)最新学习路线

​​

该路线图包含基础技能、就业必备技能、多媒体技术、六大电商APP、进阶高级技能、实战就业级设备开发,不仅补充了华为官网未涉及的解决方案

路线图适合人群:

IT开发人员:想要拓展职业边界
零基础小白:鸿蒙爱好者,希望从0到1学习,增加一项技能。
技术提升/进阶跳槽:发展瓶颈期,提升职场竞争力,快速掌握鸿蒙技术

2.视频教程+学习PDF文档

(鸿蒙语法ArkTS、TypeScript、ArkUI教程……)全球开发者的开源社区,开源代码

 纯血版鸿蒙全套学习文档(面试、文档、全套视频等)全球开发者的开源社区,开源代码

                   

鸿蒙APP开发必备

​​​

总结

参与鸿蒙开发,你要先认清适合你的方向,如果是想从事鸿蒙应用开发方向的话,可以参考本文的学习路径,简单来说就是:为了确保高效学习,建议规划清晰的学习路线

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2154324.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

线性表一(vector)

#include<bits/stdc.h> using namespace std; vector<int> a(5,2);//定义一个初始长度为5&#xff0c;每个元素值为2的可变数组 vector<char> b(3);//定义一个初始长度为3&#xff0c;每个元素为默认值的可变数组 vector<int> v;//定义一个长度为0的可…

mxnet系统架构

mxnet系统架构 MXNet 是一个高性能、灵活的深度学习框架&#xff0c;最早由李沐&#xff08;Mu Li&#xff09;等人开发&#xff0c;并且得到了 Amazon 的支持。它支持多种语言&#xff08;包括 Python、Scala、C、R、Julia、Perl 等&#xff09;&#xff0c;并以其灵活的编程…

【保奖思路】2024年华为杯研赛B题完整代码建模过程(后续会更新)

您的点赞收藏是我继续更新的最大动力&#xff01; 一定要点击如下的卡片&#xff0c;那是获取资料的入口&#xff01; 点击链接加入【2024华为杯研赛资料汇总】&#xff1a;https://qm.qq.com/q/XzdIsvbiM0https://qm.qq.com/q/XzdIsvbiM0请根据附件WLAN网络实测训练集中所提供…

python多继承 - 子类指定父类

菜鸟教程-面向对象 https://www.runoob.com/python3/python3-class.html 子类内指定父类 父类名称.__init__(self,参数1&#xff0c;参数2&#xff0c;...) 子类对象指定父类 class Parent1:def my_method(self):print("Parent1s my_method")class Parent2:def my_…

基于uni-app的计算机类面试宝设计与实现(毕业论文)

目 录 1 前言 1 1.1 研究目的与意义 1 1.2 研究现状 1 1.3 论文结构 2 2 可行性分析 3 2.1 经济可行性 3 2.2 法律可行性 3 2.3 技术可行性 4 2.4 市场可行性 4 2.5 可行性分析结论 4 3 系统需求分析 4 3.1 用户需求分析 4 3.2 系统功能分析 5 3.3 系统性能需求分析 6 4 概要设…

前端vue-ref与document.querySelector的对比

ref只在本组件中查找&#xff0c;而document.querySelector是在整个页面查找

【学习笔记】手写Tomcat 四

目录 一、Read 方法返回 -1 的问题 二、JDBC 优化 1. 创建配置文件 2. 创建工具类 3. 简化 JDBC 的步骤 三、修改密码 优化返回数据 创建修改密码的页面 注意 测试 四、优化响应动态资源 1. 创建 LoginServlet 类 2. 把登录功能的代码放到 LoginServlet 类 3. 创…

hackmyvm靶场--zon

环境 攻击机kali 靶机 未知 主机探测 因为在同一个局域网内使用ARP协议探测存活主机 靶机为192.168.56.128 端口探测 常见的80和22端口 那么一定是寻找web漏洞拿shell了 后台扫描 后台扫描常用dirsearch和gobuster,有时候小字典可能不太行&#xff0c;可以尝试换个大点…

Android SystemUI组件(07)锁屏KeyguardViewMediator分析

该系列文章总纲链接&#xff1a;专题分纲目录 Android SystemUI组件 本章关键点总结 & 说明&#xff1a; 说明&#xff1a;本章节持续迭代之前章节的思维导图&#xff0c;主要关注左侧上方锁屏分析部分即可。 为了更好理解本文的内容&#xff0c;优先说明下SystemUI中与Ke…

电力行业螺钉螺帽螺丝缺失检测数据集 voc yol

电力行业螺钉螺帽螺丝缺失检测数据集 数据集描述 该数据集旨在用于电力行业中的螺钉、螺帽、螺丝等紧固件的缺失检测任务。数据集包含了大量的图像及其对应的标注信息&#xff0c;可用于训练计算机视觉模型&#xff0c;以识别和定位电力设施中的螺钉、螺帽、螺丝等部件是否存在…

Go-知识-定时器

Go-知识-定时器 1. 介绍2. Timer使用场景2.1 设定超时时间2.2 延迟执行某个方法 3. Timer 对外接口3.1 创建定时器3.2 停止定时器3.3 重置定时器3.4 After3.5 AfterFunc 4. Timer 的实现原理4.1 Timer数据结构4.1.1 Timer4.1.2 runtimeTimer 4.2 Timer 实现原理4.2.1 创建Timer…

golang学习笔记1-go程序执行流程

声明&#xff1a;本人已有C&#xff0c;C,Python基础&#xff0c;只写本人认为的重点&#xff0c;方便自己回顾。 命令行执行go程序有两种方式&#xff0c;其流程如下图 注意第一种方式会得到可执行文件&#xff0c;第二种不会。 例1 在当前目录下编译hello.go go build hel…

更换硬盘后,电脑装完系统进不去?或PE能识别硬盘但开机/启动/BIOS识别不了硬盘解决办法

由于现在的电脑主板&#xff0c;默认都是UEFI启动&#xff0c;硬盘只有使用GUID分区表&#xff0c;主板BIOS才找得到系统引导&#xff01; 而当我们拿到一块新硬盘&#xff0c;使用分区工具默认类型分区&#xff0c;默认是MBR类型&#xff0c;所以这种分区的硬盘&#xff0c;B…

【后端开发】JavaEE初阶—线程的理解和编程实现

前言&#xff1a; &#x1f31f;&#x1f31f;本期讲解多线程的知识哟~~~&#xff0c;希望能帮到屏幕前的你。 &#x1f308;上期博客在这里&#xff1a;【后端开发】JavaEE初阶——计算机是如何工作的&#xff1f;&#xff1f;&#xff1f;-CSDN博客 &#x1f308;感兴趣的小伙…

腾讯云ssl证书到期,续期免费证书并部署

首先咱用的免费证书&#xff0c;现在最长90天有效期&#xff0c;今天又到期了&#xff0c;得及时续期避免关联资源访问受限。 我这个证书是关联了一个负载均衡和两个容器服务的&#xff08;如果您的应用是ngnix或其他的应用那和本文操作可能有点不一样&#xff09; 所以需要做…

17【Protues单片机仿真】基于51单片机的太阳能智能谷物翻晒机器人

目录 一、主要功能 二、硬件资源 三、程序编程 四、实现现象 一、主要功能 基于51单片机&#xff0c;避障&#xff0c;低于50CM报警&#xff0c;LED灯亮起&#xff0c;自动翻晒用光敏电阻&#xff0c;光照强度大&#xff0c;电机转动&#xff0c;相当于翻晒粮食&#xff0…

【python设计模式7】行为型模式2

目录 策略模式 模板方法模式 策略模式 定义一个个算法&#xff0c;把它们封装起来&#xff0c;并且使它们可以相互替换。本模式使得算法可独立于使用它的客户而变化。角色有&#xff1a;抽象策略、具体策略和上下文。 from abc import abstractmethod, ABCMeta from datetim…

2024年最新Redis内存数据库主从复制、哨兵模式、集群部署等详细教程(更新中)

Centos 安装 Redis 检查安装 GCC 环境 [rootVM-4-17-centos ~]# gcc --version gcc (GCC) 8.5.0 20210514 (Red Hat 8.5.0-4) Copyright (C) 2018 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; no…

数据库(选择题)

基本概念 数据库&#xff08;DB&#xff09;&#xff1a;长期存储在计算机内的、有组织的、可共享的数据集合。 数据库管理系统&#xff08;DBMS&#xff09;&#xff1a;它是数据库的机构&#xff0c;是一个系统软件&#xff0c;负责数据库中的数据组织、数据操纵、数据维护…

深度学习03-神经网络02-激活函数

可以使用这个进行跳转链接​​​​​​​http://playground.tensorflow.org/#activationrelu&batchSize11&datasetspiralDatasetreg-gauss&learningRate0.01ularizationRate0.1&noise0&networkShape7,5,4,3,2&seed0.54477&showTestDatafalse&d…