1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > android按住录音按钮_Android仿微信录音功能

android按住录音按钮_Android仿微信录音功能

时间:2020-09-30 07:22:04

相关推荐

android按住录音按钮_Android仿微信录音功能

提要:需求是开发类似微信发语音的功能,没有语音转文字。网上看了一些代码,不能拿来直接用,部分代码逻辑有问题,所以想把自己的代码贴出来,仅供参考。

功能:

a、设置最大录音时长和录音倒计时(为了方便测试,最大时长设置为15秒,开始倒计时设置为7秒)

b、在录音之前检查录音和存储权限

源码:

1、录音对话框管理类DialogManager:

/**

* 功能:录音对话框管理类

*/

public class DialogManager {

private AlertDialog.Builder builder;

private AlertDialog dialog;

private ImageView mIcon;

private ImageView mVoice;

private TextView mLabel;

private Context context;

/**

* 构造方法

*

* @param context Activity级别的Context

*/

public DialogManager(Context context) {

this.context = context;

}

/**

* 显示录音的对话框

*/

public void showRecordingDialog() {

builder = new AlertDialog.Builder(context, R.style.AudioRecorderDialogStyle);

LayoutInflater inflater = LayoutInflater.from(context);

View view = inflater.inflate(R.layout.audio_recorder_dialog, null);

mIcon = view.findViewById(R.id.iv_dialog_icon);

mVoice = view.findViewById(R.id.iv_dialog_voice);

mLabel = view.findViewById(R.id.tv_dialog_label);

builder.setView(view);

dialog = builder.create();

dialog.show();

dialog.setCanceledOnTouchOutside(false);

}

/**

* 正在播放时的状态

*/

public void recording() {

if (dialog != null && dialog.isShowing()) { //显示状态

mIcon.setVisibility(View.VISIBLE);

mVoice.setVisibility(View.VISIBLE);

mLabel.setVisibility(View.VISIBLE);

mIcon.setImageResource(R.drawable.ic_audio_recorder);

mVoice.setImageResource(R.drawable.ic_audio_v1);

mLabel.setText(R.string.audio_record_dialog_up_to_cancel);

}

}

/**

* 显示想取消的对话框

*/

public void wantToCancel() {

if (dialog != null && dialog.isShowing()) { //显示状态

mIcon.setVisibility(View.VISIBLE);

mVoice.setVisibility(View.GONE);

mLabel.setVisibility(View.VISIBLE);

mIcon.setImageResource(R.drawable.ic_audio_cancel);

mLabel.setText(R.string.audio_record_dialog_release_to_cancel);

}

}

/**

* 显示时间过短的对话框

*/

public void tooShort() {

if (dialog != null && dialog.isShowing()) { //显示状态

mIcon.setVisibility(View.VISIBLE);

mVoice.setVisibility(View.GONE);

mLabel.setVisibility(View.VISIBLE);

mLabel.setText(R.string.audio_record_dialog_too_short);

}

}

// 显示取消的对话框

public void dismissDialog() {

if (dialog != null && dialog.isShowing()) { //显示状态

dialog.dismiss();

dialog = null;

}

}

/**

* 显示更新音量级别的对话框

*

* @param level 1-7

*/

public void updateVoiceLevel(int level) {

if (dialog != null && dialog.isShowing()) { //显示状态

mIcon.setVisibility(View.VISIBLE);

mVoice.setVisibility(View.VISIBLE);

mLabel.setVisibility(View.VISIBLE);

int resId = context.getResources().getIdentifier("ic_audio_v" + level, "drawable", context.getPackageName());

mVoice.setImageResource(resId);

}

}

public void updateTime(int time) {

if (dialog != null && dialog.isShowing()) { //显示状态

mIcon.setVisibility(View.VISIBLE);

mVoice.setVisibility(View.VISIBLE);

mLabel.setVisibility(View.VISIBLE);

mLabel.setText(time + "s");

}

}

}

2、录音管理类AudioManager

/**

* 功能:录音管理类

*/

public class AudioManager {

private MediaRecorder mMediaRecorder;

private String mDir;

private String mCurrentFilePath;

private static AudioManager mInstance;

private boolean isPrepared;

private AudioManager(String dir) {

this.mDir = dir;

}

//单例模式:在这里实例化AudioManager并传入录音文件地址

public static AudioManager getInstance(String dir) {

if (mInstance == null) {

synchronized (AudioManager.class) {

if (mInstance == null) {

mInstance = new AudioManager(dir);

}

}

}

return mInstance;

}

/**

* 回调准备完毕

*/

public interface AudioStateListener {

void wellPrepared();

}

public AudioStateListener mListener;

/**

* 回调方法

*/

public void setOnAudioStateListener(AudioStateListener listener) {

mListener = listener;

}

/**

* 准备

*/

public void prepareAudio() {

try {

isPrepared = false;

File dir = FileUtils.createNewFile(mDir);

String fileName = generateFileName();

File file = new File(dir, fileName);

mCurrentFilePath = file.getAbsolutePath();

Logger.t("AudioManager").i("audio file name :" + mCurrentFilePath);

mMediaRecorder = new MediaRecorder();

//设置输出文件

mMediaRecorder.setOutputFile(mCurrentFilePath);

//设置MediaRecorder的音频源为麦克风

mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);

//设置音频格式

mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);

//设置音频的格式为AAC

mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);

//准备录音

mMediaRecorder.prepare();

//开始

mMediaRecorder.start();

//准备结束

isPrepared = true;

if (mListener != null) {

mListener.wellPrepared();

}

} catch (Exception e) {

e.printStackTrace();

}

}

/**

* 随机生成文件的名称

*/

private String generateFileName() {

return UUID.randomUUID().toString() + ".m4a";

}

public int getVoiceLevel(int maxLevel) {

if (isPrepared) {

try {

//获得最大的振幅getMaxAmplitude() 1-32767

return maxLevel * mMediaRecorder.getMaxAmplitude() / 32768 + 1;

} catch (Exception e) {

}

}

return 1;

}

/**

* 释放资源

*/

public void release() {

if (mMediaRecorder != null) {

mMediaRecorder.stop();

mMediaRecorder.release();

mMediaRecorder = null;

}

}

public void cancel() {

release();

if (mCurrentFilePath != null) {

File file = new File(mCurrentFilePath);

FileUtils.deleteFile(file);

mCurrentFilePath = null;

}

}

public String getCurrentFilePath() {

return mCurrentFilePath;

}

}

3、自定义录音按钮AudioRecorderButton

/**

* 功能:录音按钮

*/

public class AudioRecorderButton extends AppCompatButton {

private Context mContext;

//取消录音Y轴位移

private static final int DISTANCE_Y_CANCEL = 80;

//录音最大时长限制

private static final int AUDIO_RECORDER_MAX_TIME = 15;

//录音倒计时时间

private static final int AUDIO_RECORDER_COUNT_DOWN = 7;

//状态

private static final int STATE_NORMAL = 1;// 默认的状态

private static final int STATE_RECORDING = 2;// 正在录音

private static final int STATE_WANT_TO_CANCEL = 3;// 希望取消

//当前的状态

private int mCurrentState = STATE_NORMAL;

//已经开始录音

private boolean isRecording = false;

//是否触发onLongClick

private boolean mReady;

private DialogManager mDialogManager;

private AudioManager mAudioManager;

private android.media.AudioManager audioManager;

public AudioRecorderButton(Context context) {

this(context, null);

}

public AudioRecorderButton(Context context, AttributeSet attrs) {

super(context, attrs);

this.mContext = context;

mDialogManager = new DialogManager(context);

audioManager = (android.media.AudioManager) context.getSystemService(Context.AUDIO_SERVICE);

String dir = SdUtils.getCustomFolder("Audios");//创建文件夹

mAudioManager = AudioManager.getInstance(dir);

mAudioManager.setOnAudioStateListener(new AudioManager.AudioStateListener() {

@Override

public void wellPrepared() {

mHandler.sendEmptyMessage(MSG_AUDIO_PREPARED);

}

});

//按钮长按 准备录音 包括start

setOnLongClickListener(new OnLongClickListener() {

@Override

public boolean onLongClick(View v) {

//先判断有没有录音和存储权限,有则开始录音,没有就申请权限

int hasAudioPermission = ContextCompat.checkSelfPermission(mContext, Manifest.permission.RECORD_AUDIO);

int hasStoragePermission = ContextCompat.checkSelfPermission(mContext, Manifest.permission.WRITE_EXTERNAL_STORAGE);

if (hasAudioPermission == PackageManager.PERMISSION_GRANTED && hasStoragePermission == PackageManager.PERMISSION_GRANTED) {

mReady = true;

mAudioManager.prepareAudio();

} else {

RxPermissions permissions = new RxPermissions((FragmentActivity) mContext);

Disposable disposable = permissions.request(Manifest.permission.RECORD_AUDIO, Manifest.permission.WRITE_EXTERNAL_STORAGE)

.subscribe(new Consumer() {

@Override

public void accept(Boolean granted) {

if (!granted) {

ToastUtils.showShort("发送语音功能需要赋予录音和存储权限");

}

}

});

}

return true;

}

});

}

private static final int MSG_AUDIO_PREPARED = 0X110;

private static final int MSG_VOICE_CHANGED = 0X111;

private static final int MSG_DIALOG_DISMISS = 0X112;

private static final int MSG_TIME_OUT = 0x113;

private static final int UPDATE_TIME = 0x114;

private boolean mThreadFlag = false;

//录音时长

private float mTime;

//获取音量大小的Runnable

private Runnable mGetVoiceLevelRunnable = new Runnable() {

@Override

public void run() {

while (isRecording) {

try {

Thread.sleep(100);

mTime += 0.1f;

mHandler.sendEmptyMessage(MSG_VOICE_CHANGED);

if (mTime >= AUDIO_RECORDER_MAX_TIME) {//如果时间超过60秒,自动结束录音

while (!mThreadFlag) {//记录已经结束了录音,不需要再次结束,以免出现问题

mDialogManager.dismissDialog();

mAudioManager.release();

if (audioFinishRecorderListener != null) {

//先回调,再Reset,不然回调中的时间是0

audioFinishRecorderListener.onFinish(mTime, mAudioManager.getCurrentFilePath());

mHandler.sendEmptyMessage(MSG_TIME_OUT);

}

mThreadFlag = !mThreadFlag;

}

isRecording = false;

} else if (mTime >= AUDIO_RECORDER_COUNT_DOWN) {

mHandler.sendEmptyMessage(UPDATE_TIME);

}

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

};

private Handler mHandler = new Handler(new Handler.Callback() {

@Override

public boolean handleMessage(Message msg) {

switch (msg.what) {

case MSG_AUDIO_PREPARED:

mDialogManager.showRecordingDialog();

isRecording = true;

new Thread(mGetVoiceLevelRunnable).start();

break;

case MSG_VOICE_CHANGED:

mDialogManager.updateVoiceLevel(mAudioManager.getVoiceLevel(7));

break;

case MSG_DIALOG_DISMISS:

mDialogManager.dismissDialog();

break;

case MSG_TIME_OUT:

reset();

break;

case UPDATE_TIME:

int countDown = (int) (AUDIO_RECORDER_MAX_TIME - mTime);

mDialogManager.updateTime(countDown);

break;

}

return true;

}

});

/**

* 录音完成后的回调

*/

public interface AudioFinishRecorderListener {

/**

* @param seconds 时长

* @param filePath 文件

*/

void onFinish(float seconds, String filePath);

}

private AudioFinishRecorderListener audioFinishRecorderListener;

public void setAudioFinishRecorderListener(AudioFinishRecorderListener listener) {

audioFinishRecorderListener = listener;

}

android.media.AudioManager.OnAudioFocusChangeListener onAudioFocusChangeListener = new android.media.AudioManager.OnAudioFocusChangeListener() {

@Override

public void onAudioFocusChange(int focusChange) {

if (focusChange == android.media.AudioManager.AUDIOFOCUS_LOSS) {

audioManager.abandonAudioFocus(onAudioFocusChangeListener);

}

}

};

public void myRequestAudioFocus() {

audioManager.requestAudioFocus(onAudioFocusChangeListener, android.media.AudioManager.STREAM_MUSIC, android.media.AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);

}

@Override

public boolean onTouchEvent(MotionEvent event) {

Logger.t("AudioManager").i("x :" + event.getX() + "-Y:" + event.getY());

switch (event.getAction()) {

case MotionEvent.ACTION_DOWN:

mThreadFlag = false;

isRecording = true;

changeState(STATE_RECORDING);

myRequestAudioFocus();

break;

case MotionEvent.ACTION_MOVE:

if (isRecording) {

//根据想x,y的坐标,判断是否想要取消

if (event.getY() < 0 && Math.abs(event.getY()) > DISTANCE_Y_CANCEL) {

changeState(STATE_WANT_TO_CANCEL);

} else {

changeState(STATE_RECORDING);

}

}

break;

case MotionEvent.ACTION_UP:

//如果longClick 没触发

if (!mReady) {

reset();

return super.onTouchEvent(event);

}

//触发了onLongClick 没准备好,但是已经prepared已经start

//所以消除文件夹

if (!isRecording || mTime < 1.0f) {

mDialogManager.tooShort();

mAudioManager.cancel();

mHandler.sendEmptyMessageDelayed(MSG_DIALOG_DISMISS, 1000);

} else if (mCurrentState == STATE_RECORDING) {//正常录制结束

mDialogManager.dismissDialog();

mAudioManager.release();

if (audioFinishRecorderListener != null) {

audioFinishRecorderListener.onFinish(mTime, mAudioManager.getCurrentFilePath());

}

} else if (mCurrentState == STATE_WANT_TO_CANCEL) {

mDialogManager.dismissDialog();

mAudioManager.cancel();

}

reset();

audioManager.abandonAudioFocus(onAudioFocusChangeListener);

break;

}

return super.onTouchEvent(event);

}

/**

* 恢复状态 标志位

*/

private void reset() {

isRecording = false;

mTime = 0;

mReady = false;

changeState(STATE_NORMAL);

}

/**

* 改变状态

*/

private void changeState(int state) {

if (mCurrentState != state) {

mCurrentState = state;

switch (state) {

case STATE_NORMAL:

setText(R.string.audio_record_button_normal);

break;

case STATE_RECORDING:

if (isRecording) {

mDialogManager.recording();

}

setText(R.string.audio_record_button_recording);

break;

case STATE_WANT_TO_CANCEL:

mDialogManager.wantToCancel();

setText(R.string.audio_record_button_cancel);

break;

}

}

}

}

4、DialogStyle

true

@style/ActivityAnimTheme

@style/MenuStyle

@android:color/transparent

true

@null

true

true

@style/ActivityDialogAnimation

false

@anim/fade_in

@anim/fade_out

5、DialogLayout

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:background="@drawable/audio_recorder_dialog_bg"

android:gravity="center"

android:orientation="vertical"

android:padding="20dp">

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:orientation="horizontal">

android:id="@+id/iv_dialog_icon"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:src="@drawable/ic_audio_recorder" />

android:id="@+id/iv_dialog_voice"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:src="@drawable/ic_audio_v1" />

android:id="@+id/tv_dialog_label"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_marginTop="15dp"

android:text="@string/audio_record_dialog_up_to_cancel"

android:textColor="@color/white"

android:textSize="15dp" />

6、用到的字符串

按住说话

松开结束

松开手指取消发送

手指上划,取消发送

松开手指,取消发送

录音时间过短

7、使用:按钮的样式不需要写在自定义Button中,方便使用

android:id="@+id/btn_audio_recorder"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:text="@string/audio_record_button_normal" />

AudioRecorderButton audioRecorderButton = findViewById(R.id.btn_audio_recorder);

audioRecorderButton.setAudioFinishRecorderListener(new AudioRecorderButton.AudioFinishRecorderListener() {

@Override

public void onFinish(float seconds, String filePath) {

Logger.i(seconds + "秒:" + filePath);

}

});

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。