鸿蒙开发融云demo录制语音消息

鸿蒙开发融云demo录制语音消息

融云鸿蒙版是不带UI的,得自己一步步搭建。录制语音,长按录制效果是最难弄的。还有录制声音的声音大小波动。

这次来讲如何长按录制语音消息

一、思路:

自定义TouchEvent,然后调用融云的录制语音方法。声音大小用AudioRecorder.getInstance().avRecorder?.getAudioCapturerMaxAmplitude

二、效果图:
三、关键代码:
typescript 复制代码
// 播放语音的播放器
  // 区分语音还是文字输入状态
  @State isVoiceInput:boolean = false
  microphonePermissions: Permissions = 'ohos.permission.MICROPHONE';
  hasMicrophonePermissions:boolean = false
  // 是否正在请求麦克风权限
  isRequestMicrophonePermissions:boolean = false
  // Column高度最大值,用于长按是声音的振幅
  @State yMax: number = 0;
  // Column高度最小值
  @State yMin: number = 0;
  // 声音文件名称,不能重复,否则播放自己本地语音,只会播放最后一条
  voiceName:string = ''
  // 当前录音时间,用于录制到50s后倒计时
  currentRecordVoiceTime:number = 0
  @State countDownVoiceText:string = ''
  maxMicVolumeCountId: number = 0
  // 开始录制时的时间戳
  audioTapTs: number = 0;
  audioFile: fs.File | null = null;
  // 创建音频录制与播放实例
  avPlayer?:media.AVPlayer
  @State voicePlayState: AnimationStatus = AnimationStatus.Initial
  @State voicePlayMessageId:number = 0
  // 按住说话 录音模态
  @State
  showTalkContainer: boolean = false
  // 长按状态
  @State
  pressCancelVoicePostText: PressCancelVoicePostText = PressCancelVoicePostText.none
  // "x "的坐标
  xScreenOffset: ScreenOffset = {
    x: 0,
    y: 0,
    width: 0,
    height: 0
  }

  // 按住说话 持续触发
  onPressTalk = async (event: TouchEvent) => {
    if (event.type === TouchType.Down) {
      this.currentRecordVoiceTime = 0
      this.countDownVoiceText = ''
      PermissionUtil.checkPermissions(this.microphonePermissions).then((result:boolean) => {
        if (result) {
          // 有权限
          this.hasMicrophonePermissions = true
          this.isRequestMicrophonePermissions = false
          // 手指按下时触发
          this.pressCancelVoicePostText = PressCancelVoicePostText.presssing
          // 按下
          this.showTalkContainer = true
          //  开始录音
          this.startRecordVoice()
        } else {
          this.isRequestMicrophonePermissions = true
          // 问麦克风权限
          PermissionUtil.requestPermissionsEasy(this.microphonePermissions).then((result:boolean)=>{
            if (result) {
              // 有权限
              this.hasMicrophonePermissions = true
              // 这里先不录,因为用户放开手去点击允许权限了
              //this.startRecordVoice()
            } else {
              this.hasMicrophonePermissions = false
            }
          })
        }
      })
      

    } else if (event.type === TouchType.Move) {
      if (this.hasMicrophonePermissions && !this.isRequestMicrophonePermissions) {
        // 手指移动时持续触发
        this.pressCancelVoicePostText = PressCancelVoicePostText.presssing
        // 获取当前手指的坐标
        const x = event.touches[0].displayX
        const y = event.touches[0].displayY
        // 判断是否碰到了 "X"
        let isTouchX = this.xScreenOffset.x <= x && this.xScreenOffset.x + this.xScreenOffset.width >= x &&
          this.xScreenOffset.y <= y && this.xScreenOffset.y + this.xScreenOffset.width >= y

        if (isTouchX) {
          // 取消发送
          this.pressCancelVoicePostText = PressCancelVoicePostText.cancelVoice
        }
      }

    } else if (event.type === TouchType.Up) {
      // 松开手
      if (this.showTalkContainer) {
        this.showTalkContainer = false
        clearInterval(this.maxMicVolumeCountId)
        animateTo({ duration: 0 }, () => {
          this.yMax = 0
          this.yMin = 0
        })
        if (this.hasMicrophonePermissions && !this.isRequestMicrophonePermissions) {
          if (this.pressCancelVoicePostText === PressCancelVoicePostText.cancelVoice) {
            // 取消发送
            AudioRecorder.getInstance().stopRecordingProcess()
          } else {
            // 发送录音
            this.recordAudioEndAndSendMessage()
          }
        }
      }
    }
  }
typescript 复制代码
// 正在说话 页面布局
  @Builder
  TalkContainerBuilder() {
    Column() {
      //   1 中心的提示   显示波浪线
      Column() {
          // 声纹
        ButtonWithWaterRipples({ yMax: this.yMax, yMin: this.yMin })
        if (this.countDownVoiceText){
          Text(`${this.countDownVoiceText}"后将停止录音`)
            .fontColor($r('app.color.color_white'))
            .margin({
              top:10
            })
        }
      }
      .height(80)
      .width("50%")
      .backgroundColor(this.pressCancelVoicePostText === PressCancelVoicePostText.cancelVoice ? Color.Red : "#95EC6A")
      .position({
        top: "40%",
        left: "50%"
      })
      .translate({
        x: "-50%"
      })
      .borderRadius(10)
      .justifyContent(FlexAlign.Center)
      .alignItems(HorizontalAlign.Center)

      //   2 取消和转文字
      Column({space:30}) {

        // 3  松开发送
        Text(this.pressCancelVoicePostText === PressCancelVoicePostText.cancelVoice ? '取消发送' : "松开发送")
          .fontColor("#fff")
          .width("100%")
          .textAlign(TextAlign.Center)

          Text("X")
            .fontSize(20)
            .width(60)
            .height(60)
            .borderRadius(30)
            .fontColor(this.pressCancelVoicePostText === PressCancelVoicePostText.cancelVoice ? "#000" : "#ccc")
            .backgroundColor(this.pressCancelVoicePostText === PressCancelVoicePostText.cancelVoice ? "#fff" : "#333")
            .textAlign(TextAlign.Center)
            .align(Alignment.Center)
            .fontColor("#ccc")
            .id("aabb")
            .onAppear(() => {
              let modePosition: componentUtils.ComponentInfo = componentUtils.getRectangleById("aabb");
              this.xScreenOffset.x = px2vp(modePosition.screenOffset.x)
              this.xScreenOffset.y = px2vp(modePosition.screenOffset.y)
              this.xScreenOffset.width = px2vp(modePosition.size.width)
              this.xScreenOffset.height = px2vp(modePosition.size.height)
            })
      }
      .width("100%")
      .position({
        bottom: "23%"
      })
      .padding({
        left: 60, right: 60
      })

      //   4 底部白色大球
      Row() {

      }
      .width(600)
      .height(600)
      .backgroundColor("#fff")
      .position({
        bottom: 0,
        left: "50%"
      })
      .translate({
        x: "-50%",
        y: "70%"
      })
      .borderRadius("50%")

    }
    .width("100%")
    .height("100%")
    .backgroundColor("rgba(0,0,0,0.5)")
  }
四、鸿蒙融云Demo源码结构图:

有问题或者需要完整源码demo的私信我

相关推荐
鸿蒙自习室3 小时前
鸿蒙多线程开发——线程间数据通信对象02
ui·harmonyos·鸿蒙
SuperHeroWu75 小时前
【HarmonyOS】鸿蒙应用接入微博分享
华为·harmonyos·鸿蒙·微博·微博分享·微博sdk集成·sdk集成
zhangjr05758 小时前
【HarmonyOS Next】鸿蒙实用装饰器一览(一)
前端·harmonyos·arkts
诗歌难吟46415 小时前
初识ArkUI
harmonyos
SameX15 小时前
HarmonyOS Next 设备安全特性深度剖析学习
harmonyos
郭梧悠16 小时前
HarmonyOS(57) UI性能优化
ui·性能优化·harmonyos
郝晨妤1 天前
鸿蒙原生应用开发元服务 元服务是什么?和App的关系?(保姆级步骤)
android·ios·华为od·华为·华为云·harmonyos·鸿蒙
Peace*1 天前
HarmonyOs鸿蒙开发实战(16)=>沉浸式效果第一种方案一窗口全屏布局方案
harmonyos·鸿蒙·鸿蒙系统
howard20051 天前
鸿蒙实战:页面跳转传参
harmonyos·跳转·router·传参
遇到困难睡大觉哈哈2 天前
ArkTS组件结构和状态管理
鸿蒙