【android 安卓 模仿豆包语音条效果】

语音条view 白色的一排竖线21个,通过setEffect();方法设置音量,第一个参数是说话的时候当时音量的值,第二个参数是音量的最大值;

在这里插入代码片
package com.example.view;import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;import java.util.Random;public class LineSoundEffectView extends View {private Paint paint;// dp转px的工具,自己网上找个public final int ticksWidth = DensityUtils.dip2px(getContext(), 3f);public final int dividerWidth = DensityUtils.dip2px(getContext(), 5f);public final int ticksMaxHeight = DensityUtils.dip2px(getContext(), 30f);public final int ticksMinHeight = DensityUtils.dip2px(getContext(), 6f);public final int ticksNumber = 21;public final int fixOffset = (ticksMaxHeight - ticksMinHeight) / 2;// 计算总宽度public final int totalWidth = ticksWidth * ticksNumber + (dividerWidth * ticksNumber - 1);public LineSoundEffectView(Context context) {super(context);init();}public LineSoundEffectView(Context context, AttributeSet attrs) {super(context, attrs);init();}public LineSoundEffectView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init();}private void init() {paint = new Paint();paint.setColor(Color.WHITE);paint.setAntiAlias(true);paint.setDither(true);offsetVertical = fixOffset;invalidate();}@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);}private int offsetVertical = 0;private int totalNum = 21;@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {int desiredWidth = totalWidth; // 假设我们想要设置的宽度为200pxint desiredHeight = ticksMaxHeight; // 假设我们想要设置的高度为200px// 设置实际的宽度和高度setMeasuredDimension(desiredWidth, desiredHeight);}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);for (int i = 0; i < totalNum; i++) {int topY = offsetVertical;int bottomY = ticksMaxHeight - offsetVertical < ticksMinHeight ? ticksMinHeight :ticksMaxHeight - offsetVertical;if (i < 4) {topY = fixOffset;bottomY = ticksMaxHeight - fixOffset;paint.setAlpha((int) ((i + 1) * 255 / 6f));} else if (i >= totalNum - 4) {topY = fixOffset;bottomY = ticksMaxHeight - fixOffset;paint.setAlpha((int) ((totalNum - i) * 255 / 5f));} else {// random 越大,音波越小int random = offsetVertical <= fixOffset ? i % 2 == 0 ? Math.abs(i < totalNum / 2 ? totalNum / 2 - i : i - totalNum / 2) : 0:Math.abs(i < totalNum / 2 ? totalNum / 2 - i : i - totalNum / 2)%5;int i1 = offsetVertical + random > fixOffset ? fixOffset : offsetVertical + random;topY = i1;bottomY = ticksMaxHeight - i1;paint.setAlpha(255);}canvas.drawRoundRect(new RectF((dividerWidth + ticksWidth) * i, topY, (dividerWidth + ticksWidth) * i + ticksWidth, bottomY), ticksWidth / 2, ticksWidth / 2, paint);
//            }}}@Overridepublic boolean onTouchEvent(MotionEvent event) {if (event.getAction() == MotionEvent.ACTION_DOWN) {// 重绘视图invalidate();return true;}return super.onTouchEvent(event);}public void setEffect(int value, int maxValue) {offsetVertical = (int) (fixOffset * (1 - (value * 1f / maxValue)));invalidate();}
}

松手发送,上移取消代码

 binding.tvChatVoice.setOnTouchListener((v, motionEvent) -> {switch (motionEvent.getAction()) {case MotionEvent.ACTION_DOWN:downY = motionEvent.getY();startVoice();break;case MotionEvent.ACTION_CANCEL: // 首次开权限时会走这里,录音取消case MotionEvent.ACTION_UP:if (mIat != null) {if (isCanceledVoiceSendOp) {mIat.cancel();endVoice();} else {mIat.stopListening();}}break;case MotionEvent.ACTION_MOVE: // 滑动手指float moveY = motionEvent.getY();LogUtils.e("move-------downY - moveY=" + (downY - moveY));if (downY != 0 && downY - moveY > 100) {if (!isCanceledVoiceSendOp) {// 震动反馈binding.tvChatVoice.setHapticFeedbackEnabled(true);binding.tvChatVoice.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);}isCanceledVoiceSendOp = true;binding.llChatEffect.setBackgroundResource(R.drawable.shape_chat_voice_effect_cancel_bg);binding.tvChatVoiceEffectTips.setText("松手取消");binding.tvChatVoiceEffectTips.setTextColor(getResources().getColor(R.color.color_FE3750));}if (downY - moveY < 20) {if (isCanceledVoiceSendOp) {// 震动反馈binding.tvChatVoice.setHapticFeedbackEnabled(true);binding.tvChatVoice.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);}isCanceledVoiceSendOp = false;binding.tvChatVoiceEffectTips.setText("松手发送,上移取消");binding.tvChatVoiceEffectTips.setTextColor(getResources().getColor(R.color.color_8B8B8B));binding.llChatEffect.setBackgroundResource(R.drawable.shape_chat_voice_effect_bg);}break;}return true;});
/*** 开始语音输入*/private void startVoice() {if (!isAttachedActivityValid()) {return;}binding.tvChatVoice.setHapticFeedbackEnabled(true);binding.tvChatVoice.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);// 取消上次请求cancelPreQuestionRequest();if (ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {requestPermissionLauncher.launch(Manifest.permission.RECORD_AUDIO);return;}binding.tvChatVoiceEffectTips.setVisibility(View.VISIBLE);binding.tvChatVoiceEffectTips.setText("松手发送,上移取消");binding.tvChatVoiceEffectTips.setTextColor(getResources().getColor(R.color.color_8B8B8B));binding.llChatEffect.setVisibility(View.VISIBLE);binding.llFooter.setBackgroundResource(R.drawable.ic_chat_voice_effect_bottom_bg);
//        binding.ivChatEffect.setImageResource(R.drawable.ic_chat_effect_1);mVoiceTextBuffer.setLength(0);// 不显示听写对话框int ret = mIat.startListening(new RecognizerListener() {@Overridepublic void onBeginOfSpeech() {// 此回调表示:sdk内部录音机已经准备好了,用户可以开始语音输入}@Overridepublic void onError(SpeechError error) {// Tips:// 错误码:10118(您没有说话),可能是录音机权限被禁,需要提示用户打开应用的录音权限。
//                Log.d(TAG, "onError " + error.getPlainDescription(true));toastCenter(error.getPlainDescription(false));endVoice();}@Overridepublic void onEndOfSpeech() {// 此回调表示:检测到了语音的尾端点,已经进入识别过程,不再接受语音输入// TODO 显示按住说话endVoice();}@Overridepublic void onResult(RecognizerResult results, boolean isLast) {String speechText = results.getResultString();LogUtils.e(speechText);if (isLast) {LogUtils.e("aiChat-------onResult 结束");endVoice();}mVoiceTextBuffer.append(speechText);if (isLast) {if (TextUtils.isEmpty(mVoiceTextBuffer.toString())) {new CommonSureDialog(getActivity(), "听不清楚,请重新说一遍!", new View.OnClickListener() {@Overridepublic void onClick(View v) {}}).show();} else {// 语音搜索sendChatMsg(mVoiceTextBuffer.toString(), null);}}}@Overridepublic void onVolumeChanged(int volume, byte[] data) {binding.lineSoundEffectView.setEffect(volume, 30);LogUtils.e("aiChat-------当前正在说话,音量大小 = " + volume + " 返回音频数据 = " + data.length);}@Overridepublic void onEvent(int eventType, int arg1, int arg2, Bundle obj) {}});if (ret != ErrorCode.SUCCESS) {toastCenter("听写启用失败,错误码ret=" + ret);}}/*** 结束语音输入*/private void endVoice() {binding.llChatVoice.setVisibility(View.VISIBLE);binding.llChatEffect.setVisibility(View.GONE);binding.llFooter.setBackgroundResource(R.drawable.ic_chat_bottom_bg);binding.tvChatVoiceEffectTips.setVisibility(View.GONE);binding.tvChatVoiceEffectTips.setText("松手发送,上移取消");binding.tvChatVoiceEffectTips.setTextColor(getResources().getColor(R.color.color_8B8B8B));binding.llChatEffect.setBackgroundResource(R.drawable.shape_chat_voice_effect_bg);downY = 0;}// 语音听写对象private SpeechRecognizer mIat;// 初始化语音听写sdkprivate void initVoiceSDK() {// 初始化识别无UI识别对象// 使用SpeechRecognizer对象,可根据回调消息自定义界面;mIat = SpeechRecognizer.createRecognizer(getActivity(), new InitListener() {@Overridepublic void onInit(int i) {LogUtils.e("aiChat-------speechInit---i=" + i);if (i == 0 && mIat != null) {setParam();}}});}/*** 语音听写参数设置*/public void setParam() {// 清空参数mIat.setParameter(SpeechConstant.PARAMS, null);// 设置听写引擎mIat.setParameter(SpeechConstant.ENGINE_TYPE, SpeechConstant.TYPE_CLOUD);// 设置返回结果格式mIat.setParameter(SpeechConstant.RESULT_TYPE, "plain"); // plain / json// 设置语言:中文mIat.setParameter(SpeechConstant.LANGUAGE, "zh_cn");// 设置语言区域:普通话mIat.setParameter(SpeechConstant.ACCENT, "mandarin"); // mandarin:普通话//此处用于设置dialog中不显示错误码信息//mIat.setParameter("view_tips_plain","false");// 设置语音前端点:静音超时时间,即用户多长时间不说话则当做超时处理mIat.setParameter(SpeechConstant.VAD_BOS, "10000");// 设置语音后端点:后端点静音检测时间,即用户停止说话多长时间内即认为不再输入, 自动停止录音mIat.setParameter(SpeechConstant.VAD_EOS, "10000");// 设置标点符号,设置为"0"返回结果无标点,设置为"1"返回结果有标点mIat.setParameter(SpeechConstant.ASR_PTT, "1");// 设置音频保存路径,保存音频格式支持pcm、wav.mIat.setParameter(SpeechConstant.AUDIO_FORMAT, "wav");mIat.setParameter(SpeechConstant.ASR_AUDIO_PATH,getActivity().getCacheDir().getAbsolutePath() + "/msc/iat.wav");}

xml布局 底部按住说话layout:

        <androidx.constraintlayout.widget.ConstraintLayoutandroid:id="@+id/ll_footer"android:layout_width="match_parent"android:layout_height="wrap_content"android:background="@drawable/ic_chat_bottom_bg"android:orientation="vertical"android:padding="@dimen/dp_16"app:layout_constraintBottom_toBottomOf="parent"><TextViewandroid:id="@+id/tv_chat_voice_effect_tips"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginBottom="@dimen/dp_8"android:text="松开发送,上移取消"android:textColor="@color/color_8B8B8B"android:textSize="@dimen/font_size_12"android:translationZ="@dimen/dp_10"android:visibility="gone"app:layout_constraintBottom_toTopOf="@id/ll_chat_voice"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent"tools:visibility="visible" /><androidx.appcompat.widget.LinearLayoutCompatandroid:id="@+id/ll_chat_text"android:layout_width="match_parent"android:layout_height="wrap_content"android:background="@drawable/shape_item_block_bg_white_r16"android:minHeight="@dimen/dp_46"app:layout_constraintBottom_toBottomOf="parent"><EditTextandroid:id="@+id/edt_chat_content"android:layout_width="@dimen/dp_0"android:layout_height="match_parent"android:layout_gravity="top"android:layout_weight="1"android:background="@null"android:hint="发消息..."android:imeOptions="actionSend"android:lines="1"android:maxLength="200"android:paddingHorizontal="@dimen/dp_16"android:paddingVertical="@dimen/dp_12"android:singleLine="true"android:textColorHint="@color/color__999999"android:textSize="@dimen/font_size_16" /><Viewandroid:id="@+id/line_send_text"android:layout_gravity="center_vertical"android:layout_width="@dimen/line_view_1"android:visibility="gone"android:background="@color/color_DADADA"android:layout_height="@dimen/dp_16" /><ImageViewandroid:id="@+id/iv_send_text"android:padding="@dimen/dp_12"android:visibility="gone"android:src="@drawable/ic_ai_chat_send_text"android:layout_width="wrap_content"android:layout_height="wrap_content" /><ImageViewandroid:id="@+id/iv_chat_voice"android:layout_width="wrap_content"android:layout_height="wrap_content"android:padding="@dimen/dp_12"android:src="@drawable/ic_chat_voice" /></androidx.appcompat.widget.LinearLayoutCompat><androidx.constraintlayout.widget.ConstraintLayoutandroid:id="@+id/ll_chat_voice"android:layout_width="match_parent"android:layout_height="wrap_content"android:background="@drawable/shape_item_block_bg_white_r16"android:visibility="gone"app:layout_constraintBottom_toBottomOf="parent"tools:visibility="gone"><TextViewandroid:id="@+id/tv_chat_voice"android:layout_width="@dimen/dp_0"android:layout_height="match_parent"android:layout_weight="1"android:background="@null"android:gravity="center"android:paddingHorizontal="@dimen/dp_16"android:paddingVertical="@dimen/dp_12"android:text="按住 说话"android:textColor="@color/color__333333"android:textSize="@dimen/font_size_16"android:textStyle="bold"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent" /><ImageViewandroid:id="@+id/iv_chat_text"android:layout_width="wrap_content"android:layout_height="wrap_content"android:padding="@dimen/dp_12"android:src="@drawable/ic_chat_text"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintTop_toTopOf="parent" /><androidx.constraintlayout.widget.ConstraintLayoutandroid:id="@+id/ll_chat_effect"android:layout_width="@dimen/dp_0"android:layout_height="@dimen/dp_0"android:background="@drawable/shape_chat_voice_effect_bg"android:visibility="gone"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent"tools:visibility="visible"><ImageViewandroid:id="@+id/iv_chat_effect"android:layout_width="wrap_content"android:layout_height="wrap_content"android:src="@drawable/ic_chat_effect_1"android:visibility="gone"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent" /><com.kshow.kxworkbench.utils.LineSoundEffectViewandroid:id="@+id/lineSoundEffectView"android:layout_width="wrap_content"android:layout_height="wrap_content"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent" /></androidx.constraintlayout.widget.ConstraintLayout></androidx.constraintlayout.widget.ConstraintLayout></androidx.constraintlayout.widget.ConstraintLayout>

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

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

相关文章

[Go Web] Kratos 验证码业务

文章目录 1.环境准备2.验证码服务2.1 kratos 初始化验证码服务项目2.2 使用 Protobuf 定义验证码生成接口2.3 业务逻辑代码实现 1.环境准备 protoc和protoc-gen-go插件安装和kratos工具安装 protoc下载 下载二进制文件&#xff1a;https://github.com/protocolbuffers/protobu…

【Python机器学习】自动化特征选择——基于模型的特征选择

基于模型的特征选择使用一个监督机器学习模型来判断每个特征的重要性&#xff0c;并且仅保留最重要的特征。用于特征学习的监督模型不需要与用于最终建模的模型相同。特征选择模型需要为每个特征提供某种重要性度量&#xff0c;以便用这个度量对特征进行排序。决策树和基于决策…

基于YOLOv10的车辆统计跟踪与车速计算应用

文章目录 1、前言2、安装运行环境3、下载v10s模型4、代码实现5、代码详读5.1、导入必要的库5.2、识别车辆5.3、读取视频文件5.4、创建视频写入器5.5、车速计算5.6、统计车辆5.7、应用跟踪5.8、视频处理 6、目标检测系列文章 1、前言 在智能交通系统&#xff08;ITS&#xff09…

基于单片机和LabVIEW 的远程矿井水位监控系统设计

摘要 &#xff1a; 针 对 现 有 矿 井 水 位 监 控 系 统 存 在 结 构 复 杂 和 不 能 远 程 监 控 的 问 题 &#xff0c; 设计了基于单片机和&#xff2c;&#xff41;&#xff42;&#xff36;&#xff29;&#xff25;&#xff37; 的远程矿井水位监控系统 &#xff0c; 详…

密码管理器大比拼:哪款更适合你?(KeePass、Bitwarden、LastPass、1Password和Dashlane对比)

文章目录 📖 介绍 📖🏡 演示环境 🏡📒 密码管理器 📒🎯 对比🎯 付费情况🎯 安全性🎈 获取方式 🎈⚓️ 相关链接 ⚓️📖 介绍 📖 随着互联网的发展和网络安全问题的日益突出,密码管理器已经成为保障个人和企业信息安全的重要工具。本文将详细对比市面…

【计算机网络】socket通信

目录 一、Socket的概念 二、Socket的类型 2.1 TCP Socket 2.2 UDP Socket 三、 Socket通信原理 四、Socket的使用场景 五、Socket的优缺点 5.1优点 5.2 缺点 六、不同环境的socket代码解析 6.1 基于STM32的socket代码解析 6.2 基于MFC的socket代码解析 6.3 基于py…

Dataease安装,配置Jenkins自动部署

Dataease安装&#xff0c;配置Jenkins自动部署 一.安装Dataease 安装前准备&#xff1a;1.Ubuntu20.04 LTS国内源安装指定版本Docker 2.docker-compose安装 下载离线安装的安装包&#xff0c;下载地址&#xff1a;https://community.fit2cloud.com/#/download/dataease/v1-…

存储过程与函数:封装数据库逻辑的艺术(七)

引言 在上一章《事务处理》中&#xff0c;我们深入探讨了事务的ACID特性以及如何通过事务控制语句和隔离级别来确保数据的一致性和完整性。本章&#xff0c;我们将把焦点转向存储过程与函数&#xff0c;这是数据库系统中用于封装复杂业务逻辑和增强代码复用性的强大工具。通过…

人工智能AI风口已开:如何赋予UI设计与视频剪辑新生命

随着科技的浪潮不断向前推进&#xff0c;人工智能&#xff08;AI&#xff09;正以惊人的速度重塑着我们的世界&#xff0c;特别是在创意产业的核心领域——UI设计与视频剪辑中&#xff0c;AI正逐步成为驱动行业创新与变革的关键力量。在这个AI技术全面开花的新时代&#xff0c;…

C++学习笔记---串口通信

串口基础知识 DB9针的RS-232串口&#xff0c;分别是公头、母头&#xff0c;这两种串口可以连接在一起。DB9针的串口信号脚编号及信号脚的具体含义如下 串口通信可以使用3根线完成&#xff0c;对应信号脚分别是&#xff1a;2接收、3发送、5地线。对此&#xff0c;有个简单的记法…

强化学习:值函数近似【Deep Q-Network,DQN,Deep Q-learning】

强化学习笔记 主要基于b站西湖大学赵世钰老师的【强化学习的数学原理】课程&#xff0c;个人觉得赵老师的课件深入浅出&#xff0c;很适合入门. 第一章 强化学习基本概念 第二章 贝尔曼方程 第三章 贝尔曼最优方程 第四章 值迭代和策略迭代 第五章 强化学习实例分析:GridWorld…

ubuntu22.04 编译安装libcurl C++ library

1. 安装必须的依赖项 sudo apt update #sudo apt install build-essential autoconf libtool pkg-config libssl-dev libz-dev 2. 下载及编译前准备 cd /opt mkdir curl && cd curl mkdir build && mkdir install git clone https://github.com/curl/curl.git…

(番外篇)指针的一些相关习题讲解(速进,干货满满)(1)

前言&#xff1a; 我已经好久没写过博客了&#xff0c;这几天确实有点偷懒了&#xff0c;上次博客我们已经讲完了指针的部分内容&#xff0c;但我觉着没有习题是不够的&#xff0c;于是我出了这一篇番外篇&#xff0c;来让各位读者朋友们进行指针强化&#xff0c;这些题目都是小…

Python27 神经网络中的重要概念和可视化实现

1. 神经网络背后的直观知识 神经网络的工作方式非常相似&#xff1a;它接受多个输入&#xff0c;经过多个隐藏层中的多个神经元进行处理&#xff0c;并通过输出层返回结果&#xff0c;这个过程在技术上称为“前向传播”。 接下来&#xff0c;将神经网络的输出与实际输出进行比…

GIT-LFS使用

0.前言 目前git仓库有很多很大的文件需要管理&#xff0c;但是直接上传&#xff0c;每次clone的文件太大&#xff0c;所有准备使用git-lfs解决。 1、下载和安装 Git LFS 1.1、直接下载二进制包&#xff1a; Releases git-lfs/git-lfs GitHub 安装 Git LFS sudo rpm -ivh…

Spring Boot中获取请求参数的几种方式

前言 在构建现代 Web 应用时&#xff0c;处理来自客户端的请求参数是不可或缺的一部分。Spring Boot作为构建微服务应用的领先框架&#xff0c;提供了多种灵活高效的方式来获取请求参数&#xff0c;满足各种应用场景。 无论您是Spring Boot的初学者&#xff0c;还是希望更深入…

LabVIEW电涡流检测系统

开发了一种基于LabVIEW的软件与硬件结合的电涡流检测系统&#xff0c;通过同步采样技术和编码器的协同工作&#xff0c;显著提高了大型结构物的损伤检测精度和效率&#xff0c;具有良好的应用前景和实用价值。 项目背景 传统的手持式电涡流检测方法因其速度慢、灵敏度低、准确…

<sa8650>QCX 诊断模块和错误处理

<sa8650>QCX 诊断模块和错误处理 一、错误报告设计二、QCarCam API 的错误报告2.1 QCarCamRegisterEventCallback2.2 CarCamErrorInfo_t2.3 QCarCamErrorInfo_t2.4 Error ID2.4.1 QCARCAM_ERROR_WARNING2.4.2 QCARCAM_ERROR_SUBSYSTEM_FATAL2.4.3 QCARCAM_ERROR_FATAL2.4.4 Q…

Links: Challenging Puzzle Game Template(益智游戏模板)

链接:挑战益智游戏 《Links》是一款独特且具有挑战性的益智游戏,即将发布。 每个级别都会向玩家展示不同的棋盘。目标是通过移动和旋转所有棋子来连接它们。每个棋子都有自己的特点和功能-你可以移动它们,旋转它们,或者两者兼而有之。连接所有棋子,以解决难度和挑战不断增…

谷歌发布两款新Gemma 2大语言模型;阿里云开源Qwen2-72B模型荣登榜首

&#x1f989; AI新闻 &#x1f680; 谷歌发布两款新Gemma 2大语言模型 摘要&#xff1a;谷歌发布Gemma 2大语言模型&#xff0c;包括90亿和270亿参数两种版本。Gemma 2在推理性能、效率和安全性上较第一代有显著提升。27B模型的性能媲美更大规模的主流模型&#xff0c;且部署…