鸿蒙开发融云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的私信我