我写个HarmonyOS Next版本的微信聊天01

简介: 我写个HarmonyOS Next版本的微信聊天01

我写个HarmonyOS Next版本的微信聊天01

前言

代码会统一放在码云上,纯静态的完整代码会放在末尾

案例目标

这个是安卓手机上的真正的微信聊天界面功能效果

实际效果

案例功能

  1. 页面沉浸式
  2. 聊天内容滚动
  3. 输入框状态切换
  4. 聊天信息框宽度自适应
  5. 输入法避让
  6. 语音消息根据时长自动宽度
  7. canvas声纹 按住说话
  8. 手势坐标检测取消发送-语音转文字
  9. 发送文字
  10. 录音-发送语音
  11. 声音播放-语音消息
  12. AI 语音转文字

新建项目

修改项目桌面名称和图标

  1. entry\src\main\resources\zh_CN\element\string.json
{
  "string": [
    {
      "name": "module_desc",
      "value": "模块描述"
    },
    {
      "name": "EntryAbility_desc",
      "value": "description"
    },
    {
      "name": "EntryAbility_label",
      "value": "我的聊天项目" // 😄
    }
  ]
}

  1. \entry\src\main\module.json5


...
"abilities": [
  {
    "name": "EntryAbility",
    "srcEntry": "./ets/entryability/EntryAbility.ets",
    "description": "$string:EntryAbility_desc",
    "icon": "$media:chat",😄 
    ...

$media:chat 来自于 resource下的名为chat的图标

设置沉浸式

  1. 图一为默认情况下的页面布局,可以看到我们的页面是无法触及到顶部状态栏底部菜单栏
  2. 图二为设置了沉浸式效果后,布局按钮可以触及到顶部状态栏了
  3. 图三为动态获取到了顶部状态栏的高度,然后给容器添加了相应的padding,挤压布局元素到顶部状态栏的下方

设置沉浸式和获取顶部状态栏高度

\entry\src\main\ets\entryability\EntryAbility.ets

...
onWindowStageCreate(windowStage: window.WindowStage): void {
  // Main window is created, set main page for this ability
  hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate');
  windowStage.loadContent('pages/Index', (err) => {
    if (err.code) {
      hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
      return;
    }
    hilog.info(0x0000, 'testTag', 'Succeeded in loading the content.');
          //   设置应用全屏
    let windowClass: window.Window = windowStage.getMainWindowSync(); // 获取应用主窗口
    windowClass.setWindowLayoutFullScreen(true)
    let type = window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR; // 导航条避让
    let avoidArea = windowClass.getWindowAvoidArea(type);
    let bottomRectHeight = avoidArea.bottomRect.height; // 获取到导航条区域的高度
    const vpHeight = px2vp(bottomRectHeight) //  转换成 vp单位的数值
    //    把导航栏高度数据 存在全局
    AppStorage.setOrCreate("vpHeight", vpHeight)
  });
}
...

页面使用导航栏高度设置padding

@Entry
@Component
struct Index {
  @StorageProp("vpHeight")
  topHeight: number = 0
  build() {
    Column() {
      Button("按钮")
    }
    .width("100%")
    .height("100%")
    .backgroundColor(Color.Yellow)
    .padding({
      top: this.vpHeight,
    })
  }
}

搭建页面基本布局

@Entry
@Component
struct Index {
  // 状态栏高度
  @StorageProp("vpHeight")
  vpHeight: number = 0
  build() {
    Column() {
         // 1 顶部标题栏
      Row() {
        Image($r("app.media.left"))
          .width(25)
        Text("kto卋讓硪玩孫悟空")
        Image($r("app.media.more"))
          .width(25)
      }
      .width("100%")
      .justifyContent(FlexAlign.SpaceBetween)
      .border({
        width: {
          bottom: 1
        },
        color: "#ddd"
      })
      .padding(10)
       // 2 聊天滚动容器
       // 3 输入面板
   
      
    }
    .height('100%')
    .width('100%')
    .backgroundColor("#EDEDED")
    .padding({
      top: this.vpHeight + 20
    })
  }
}

页面滚动和文字信息框

6b270405cc044e0b016712b2969d1c92.png

build() {
    Column() {
      // 1 顶部标题栏 
.....
      // 2 聊天滚动容器
      Scroll() {
        Column({ space: 10 }) {
            this.chatTextBuilder("吃饭", `22:23`)
        }
        .width("100%")
        .padding(10)
        .justifyContent(FlexAlign.Start)
      }
      .layoutWeight(1)
      .align(Alignment.Top)
      .expandSafeArea([SafeAreaType.KEYBOARD], [SafeAreaEdge.BOTTOM])
    }
    .height('100%')
    .width('100%')
    .backgroundColor("#EDEDED")
    .backgroundImageSize(ImageSize.Cover)
    .padding({
      top: this.vpHeight + 20
    })
  }
  // 文字消息
  @Builder
  chatTextBuilder(text: string, time: string) {
    Column({ space: 5 }) {
      Text(time)
        .width("100%")
        .textAlign(TextAlign.Center)
        .fontColor("#666")
        .fontSize(14)
      Row() {
        Flex({ justifyContent: FlexAlign.End }) {
          Row() {
            Text(text)
              .padding(11);
            Text()
              .width(10)
              .height(10)
              .backgroundColor("#93EC6C")
              .position({
                right: 0,
                top: 15
              })
              .translate({
                x: 5,
              })
              .rotate({
                angle: 45
              });
          }
          .backgroundColor("#93EC6C")
          .margin({ right: 15 })
          .borderRadius(5);
          Image($r("app.media.avatar"))
            .width(40)
            .aspectRatio(1);
        }
        .width("100%");
      }
      .width("100%")
      .padding({
        left: 40
      })
      .justifyContent(FlexAlign.End)
    }
    .width("100%")
  }

亮点

以下代码是实现上面,自适应宽度的关键

  1. 当文字较小时,绿色聊天框宽度自适应
  2. 当文字较多时,绿色聊天框宽度自动变宽,但是不会铺满一行,微信也是这样设计的

底部消息发送框

显示输入框还是 "按住说话"

可以看到,底部消息发送框起码有三种状态

  1. 按住说话
  2. 文本输入框
  3. 文本输入框 - 发送

程序中,通过枚举决定 按住说话-文本输入框两种状态

/**
 * 当前输入状态 语音或者文本
 */
enum WXInputType {
  /**
   * 语音输入
   */
  voice = 0,
  /**
   * 文本输入
   */
  text = 1
}



显示 “发送” 按钮

另外,通过判断文本输入的长度来决定 是否显示 绿色的 发送



显示文本输入框自动获得焦点

731facfe18637835dfa9a0647695bb7d.png

设置输入时 键盘避让

不设置避让时,可以看到底部聊天被弹出的键盘顶上去了。

47463c01dbcad7891795342e5cb531ad.png

解决方法

设置拓展安全区域为软键盘区域,同时设置扩展安全区域的方向为下方区域


6d838b17d262ddd713ddc2f754c99e88.png

发送文本消息

477e3ca2ea3ac0d11e07b6d8a5ab827c.png

定义消息类型枚举

enum MessageType {
  /**
   * 声音
   */
  voice = 0,
  /**
   * 文本
   */
  text = 1
}

定义消息类

用来快速生成消息对象,可以表示语音消息和文本消息

// 消息
class ChatMessage {
  /**
   * 消息类型:【录音、文本】
   */
  type: MessageType
  /**
   * 内容 [录音-文件路径,文本-内容]
   */
  content: string
  /**
   * 消息时间
   */
  time: string
  /**
   * 声音的持续时间 单位毫秒
   */
  duration?: number
  /**
   * 录音转的文字
   */
  translateText?: string
  /**
   * 是否显示转好的文字
   */
  isShowTranslateText: boolean = false
  constructor(type: MessageType, content: string, duration?: number, translateText?: string) {
    this.type = type
    this.content = content
    const date = new Date()
    this.time = `${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}`
    this.duration = duration
    this.translateText = translateText
  }
}


定义消息数组

// 消息
  @State
  chatList: ChatMessage[] = []

定义发送文本消息的方法

// 发送文本消息
  sendTextMessage = () => {
    if (!this.textValue.trim()) {
      return
    }
    const chat = new ChatMessage(MessageType.text, this.textValue.trim())
    this.chatList.push(chat)
    this.textValue = ""
  }

注册发送文本消息事件

Button("发送")
    .backgroundColor("#08C060")
    .type(ButtonType.Normal)
    .fontColor("#fff")
    .borderRadius(5)
    .onClick(this.sendTextMessage)
 

遍历消息数组

//   2 聊天滚动容器
  Scroll() {
    Column({ space: 10 }) {
      ForEach(this.chatList, (item: ChatMessage, index: number) => {
        if (item.type === MessageType.text) {
          this.chatTextBuilder(item.content, item.time)
        }
      })
    }.width("100%")
    .padding(10)
    .justifyContent(FlexAlign.Start)
  }
  .layoutWeight(1)
  .align(Alignment.Top)
  .expandSafeArea([SafeAreaType.KEYBOARD], [SafeAreaEdge.BOTTOM])


目录
相关文章
|
27天前
|
编解码 API 数据安全/隐私保护
自学HarmonyOS Next记录:实现相册访问功能
最近我决定开发一个鸿蒙App,旨在提供更好的照片管理体验。通过使用PhotoAccessHelper API,我实现了访问、显示和管理设备相册中的照片。过程中遇到了权限不足的问题,通过在config.json中添加权限声明并编写权限检查代码得以解决。此外,我还实现了分页加载和展示照片详细信息等功能,提升了用户体验。这次开发不仅让我掌握了API的使用,也深刻体会到鸿蒙系统对用户隐私和数据安全的重视。 总结这次开发,我不仅学到了技术知识,还明白了开发者保护用户数据安全的责任。未来将继续探索更多功能,欢迎关注和收藏!
167 70
自学HarmonyOS Next记录:实现相册访问功能
|
28天前
【HarmonyOS Next开发】:ListItemGroup使用
通过使用ListItemGroup和AlphabetIndexer两种类型组件,实现带标题分类和右侧导航栏的页面
125 61
【HarmonyOS Next开发】:ListItemGroup使用
|
23天前
|
安全 数据安全/隐私保护 Android开发
HarmonyOS 5.0 Next实战应用开发—‘我的家乡’【HarmonyOS Next华为公司完全自研的操作系统】
HarmonyOS NEXT是华为自研的鸿蒙操作系统的重要版本更新,标志着鸿蒙系统首次完全脱离Linux内核及安卓开放源代码项目(AOSP),仅支持鸿蒙内核和鸿蒙系统的应用。该版本引入了“和谐美学”设计理念,通过先进的物理渲染引擎还原真实世界的光影色彩,为用户带来沉浸式体验。应用图标设计融合国画理念,采用留白和实时模糊技术展现中式美学。 HarmonyOS NEXT强化了设备间的协同能力,支持无缝切换任务,如在手机、平板或电脑间继续阅读文章或编辑文件。系统注重数据安全和隐私保护,提供数据加密和隐私权限管理功能。此外,它利用分布式技术实现跨设备资源共
108 15
HarmonyOS 5.0 Next实战应用开发—‘我的家乡’【HarmonyOS Next华为公司完全自研的操作系统】
|
23天前
|
存储 JavaScript 开发工具
基于HarmonyOS 5.0(NEXT)与SpringCloud架构的跨平台应用开发与服务集成研究【实战】
本次的.HarmonyOS Next ,ArkTS语言,HarmonyOS的元服务和DevEco Studio 开发工具,为开发者提供了构建现代化、轻量化、高性能应用的便捷方式。这些技术和工具将帮助开发者更好地适应未来的智能设备和服务提供方式。
57 8
基于HarmonyOS 5.0(NEXT)与SpringCloud架构的跨平台应用开发与服务集成研究【实战】
|
12天前
|
存储 JSON 区块链
【HarmonyOS NEXT开发——ArkTS语言】购物商城的实现【合集】
HarmonyOS应用开发使用@Component装饰器将Home结构体标记为一个组件,意味着它可以在界面构建中被当作一个独立的UI单元来使用,并且按照其内部定义的build方法来渲染具体的界面内容。txt:string定义了一个名为Data的接口,用于规范表示产品数据的结构。src:类型为,推测是用于引用资源(可能是图片资源等)的一种特定类型,用于指定产品对应的图片资源。txt:字符串类型,用于存放产品的文字描述,比如产品名称等相关信息。price:数值类型,用于表示产品的价格信息。
35 5
|
26天前
|
安全 API 数据安全/隐私保护
自学记录HarmonyOS Next DRM API 13:构建安全的数字内容保护系统
在完成HarmonyOS Camera API开发后,我深入研究了数字版权管理(DRM)技术。最新DRM API 13提供了强大的工具,用于保护数字内容的安全传输和使用。通过学习该API的核心功能,如获取许可证、解密内容和管理权限,我实现了一个简单的数字视频保护系统。该系统包括初始化DRM模块、获取许可证、解密视频并播放。此外,我还配置了开发环境并实现了界面布局。未来,随着数字版权保护需求的增加,DRM技术将更加重要。如果你对这一领域感兴趣,欢迎一起探索和进步。
85 18
|
12天前
|
开发工具 开发者 容器
【HarmonyOS NEXT开发——ArkTS语言】欢迎界面(启动加载页)的实现【合集】
从ArkTS代码架构层面而言,@Entry指明入口、@Component助力复用、@Preview便于预览,只是初窥门径,为开发流程带来些许便利。尤其动画回调与Blank组件,细节粗糙,后续定当潜心钻研,力求精进。”,字体颜色为白色,字体大小等设置与之前类似,不过动画配置有所不同,时长为。,不过这里没有看到额外的动画效果添加到这个特定的图片元素上(与前面带动画的元素对比而言)。这是一个显示文本的视图,文本内容为“奇怪的知识”,设置了字体颜色为灰色(的结构体,它代表了整个界面组件的逻辑和视图结构。
32 1
|
24天前
|
人工智能 自然语言处理 API
自学记录HarmonyOS Next的HMS AI API 13:语音合成与语音识别
在完成图像处理项目后,我计划研究HarmonyOS Next API 13中的AI语音技术,包括HMS AI Text-to-Speech和Speech Recognizer。这些API提供了强大的语音合成与识别功能,支持多语言、自定义语速和音调。通过这些API,我将开发一个支持语音输入与输出的“语音助手”原型应用,实现从语音指令解析到语音响应的完整流程。此项目不仅提高了应用的交互性,也为开发者提供了广阔的创新空间。未来,语音技术将在无障碍应用和智慧城市等领域展现巨大潜力。如果你也对语音技术感兴趣,不妨一起探索这个充满无限可能的领域。 (238字符)
91 11
|
25天前
|
存储 API 计算机视觉
自学记录HarmonyOS Next Image API 13:图像处理与传输的开发实践
在完成数字版权管理(DRM)项目后,我决定挑战HarmonyOS Next的图像处理功能,学习Image API和SendableImage API。这两个API支持图像加载、编辑、存储及跨设备发送共享。我计划开发一个简单的图像编辑与发送工具,实现图像裁剪、缩放及跨设备共享功能。通过研究,我深刻体会到HarmonyOS的强大设计,未来这些功能可应用于照片编辑、媒体共享等场景。如果你对图像处理感兴趣,不妨一起探索更多高级特性,共同进步。
74 11
|
27天前
|
传感器 测试技术 定位技术
HarmonyOS Next 模拟器安装与探索
HarmonyOS 5 的发布带来了许多新特性,尤其是 HarmonyOS Next 模拟器。本文将带你一步步了解如何安装和使用这个强大的工具,帮助你更好地进行开发,加速项目进展。通过 DevEco Studio 的 Device Manager,你可以轻松创建、配置并启动模拟器,模拟真实设备的效果,支持多窗口、跨设备测试等新特性。此外,模拟器还提供了虚拟传感器、GPS 模拟、音频输入等功能,极大地方便了开发和调试过程。掌握这些功能,能让你的开发更加高效便捷。
137 9