因为毕业设计里有需要用到录音的功能,但是又要求界面比较小巧,所以思考了许久,相出个这么办法,让一个BUTTON把播放和录音的功能全部实现(当然,其他的也可以——。——~)
1.点击的话则播放/停止播放录音
2.长按则开始录音,手指离开则停止录音
为了实现上面的效果,我们首先需要识别是点击还是长按,并且得知长按模式下按下和离开的时间。用设置setOnTouchListener的方式的话,自然可以实现,只要在按下后设置计时器就OK了,但是安卓里GestureDetector这个类提供了onSingleTapUp()和onLongPress()这两个方法帮助我们获取到简单的点击和长按事件,下面我们就测试如何利用这两个方法来分辨点击和长按模式吧
不懂GestureDetector请手搓用户手势检测-GestureDetector使用详解
两个模式的判断
好了,请看关键代码和结果
首先继承SimpleOnGestureListener并重写上面提到的两个方法
class RecordGesture extends GestureDetector.SimpleOnGestureListener {
@Override
public boolean onSingleTapUp(MotionEvent e) {
Log.v("RecordGesture","onSingleTapUp");
return super.onSingleTapUp(e);
}
@Override
public void onLongPress(MotionEvent e) {
Log.v("RecordGesture","onLongPress");
super.onLongPress(e);
}
}
然后用它来设置触摸监听,同时省略一堆东西
private RecordGesture gesture;
private GestureDetector detector;
省略。。。
gesture = new RecordGesture();
detector = new GestureDetector(context, gesture);
setOnTouchListener(this);
省略。。。
@Override
public boolean onTouch(View v, MotionEvent event) {
detector.onTouchEvent(event);
if (event.getAction() == MotionEvent.ACTION_UP) {
Log.v("RecordGesture","ACTION_UP");
}
return true;
}
下面附上结果图
点击
长按并得知手指离开的时间
很轻易的辨别出了两种模式,并且得知何时结束录音,那么就可以像这么写了,在函数内直接添加录音相关的内容即可
@Override
public boolean onTouch(View v, MotionEvent event) {
detector.onTouchEvent(event);
if (event.getAction() == MotionEvent.ACTION_UP && isRecording) {
stopSoundRecord();
}
return true;
}
class RecordGesture extends GestureDetector.SimpleOnGestureListener {
@Override
public boolean onSingleTapUp(MotionEvent e) {
Log.v("RecordGesture","onSingleTapUp");
if (isPlaying) {
stopPlayRecord();
} else {
startPlayRecord();
}
return super.onSingleTapUp(e);
}
@Override public void onLongPress(MotionEvent e) { Log.v("RecordGesture","onLongPress"); startSoundRecord(); super.onLongPress(e); } }
有人可能会问,上面的这部分代码为什么不把判断ACTION_UP放在前面呢?
detector.onTouchEvent(event);
if (event.getAction() == MotionEvent.ACTION_UP) {
Log.v("RecordGesture","ACTION_UP");
}
让我们在重写的onTouch里添加这句代码,然后触发点击事件看看
Log.v("RecordGesture",event.getAction()+" "+System.currentTimeMillis());
0=ACTION_DOWN 1=ACTION_UP 2=ACTION_MOVE
可以看到在传递过来了几次ACTION_MOVE后才触发的onSingleTapUp,所以我不赞成把判断写在前面,因为有时会有意料之外的结果,尤其是你打算在if判断句里return的时候
项目关键代码
这章博客我是准备写录音来着吧。。。。好像是,不过网上录音的博客太多了,就不多讲了,还是直接贴代码吧,100多行简单了事
import android.content.Context;
import android.media.MediaPlayer;
import android.media.MediaRecorder;
import android.os.Vibrator;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;
import java.io.IOException;
import static android.content.Context.VIBRATOR_SERVICE;
import static android.media.MediaRecorder.MEDIA_RECORDER_INFO_MAX_DURATION_REACHED;
import static android.media.MediaRecorder.MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED;
import static com.sy.audiorecord.audiorecord.RecordUtils.durationToStr;
import static com.sy.audiorecord.audiorecord.RecordUtils.getRecordDuration;
public class SoundRecord extends Button implements View.OnTouchListener {
private RecordGesture gesture;
private GestureDetector detector;
private Vibrator vibrator;//振动器
private boolean isRecording = false;//是否正在录音
private boolean isPlaying = false;//是否正在播放录音
private MediaPlayer player = null;//媒体播放器
private MediaRecorder recorder = null;//媒体录音器
private String filePath;//文件路径
private int maxDuration = 0;//录音最大时间限制
private long max_filesize_bytes = 0;//录音文件最大大小限制
public void setMaxDuration(int maxDuration) {
this.maxDuration = maxDuration;
}
public void setMax_filesize_bytes(long max_filesize_bytes) {
this.max_filesize_bytes = max_filesize_bytes;
}
public void setFilePath(String filePath) {
this.filePath = filePath;
setText(durationToStr(getRecordDuration(this.filePath)));
}
public SoundRecord(Context context) {
super(context, null);
}
public SoundRecord(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
private void init(Context context) {
vibrator = (Vibrator) context.getSystemService(VIBRATOR_SERVICE);
gesture = new RecordGesture();
detector = new GestureDetector(context, gesture);
setOnTouchListener(this);
}
@Override
public boolean onTouch(View v, MotionEvent event) {
detector.onTouchEvent(event);
if (event.getAction() == MotionEvent.ACTION_UP && isRecording) {
stopSoundRecord();
}
return true;
}
class RecordGesture extends GestureDetector.SimpleOnGestureListener {
@Override
public boolean onSingleTapUp(MotionEvent e) {
if (isPlaying) {
stopPlayRecord();
} else {
startPlayRecord();
}
return super.onSingleTapUp(e);
}
@Override
public void onLongPress(MotionEvent e) {
startSoundRecord();
super.onLongPress(e);
}
}
private void beforePlayStart() {
vibrator.vibrate(100);
}
private void afterPlayEnd() {
vibrator.vibrate(100);
}
private void startPlayRecord() {
try {
player = new MediaPlayer();
player.setDataSource(filePath);
player.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
stopPlayRecord();
}
});
player.prepare();
beforePlayStart();
player.start();
isPlaying = true;
} catch (IOException e1) {
e1.printStackTrace();
}
}
private void stopPlayRecord() {
player.stop();
player.release();
player = null;
isPlaying = false;
afterPlayEnd();
}
private void beforeRecordStart() {
vibrator.vibrate(100);
}
private void afterRecordEnd() {
vibrator.vibrate(100);
setText(durationToStr(getRecordDuration(filePath)));
}
private void startSoundRecord() {
recorder = new MediaRecorder();
recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
recorder.setOutputFile(filePath);
recorder.setMaxDuration(maxDuration);
recorder.setMaxFileSize(max_filesize_bytes);
recorder.setOnInfoListener(new MediaRecorder.OnInfoListener() {
@Override
public void onInfo(MediaRecorder mr, int what, int extra) {
if (MEDIA_RECORDER_INFO_MAX_DURATION_REACHED == what || MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED == what) {stopSoundRecord();
} } }); try { recorder.prepare(); beforeRecordStart(); recorder.start(); isRecording = true; } catch (IOException e1) { e1.printStackTrace(); } } private void stopSoundRecord() { recorder.release(); recorder = null; isRecording = false; afterRecordEnd(); }}
RecordUtils类
public class RecordUtils {
public static int getRecordDuration(String filePath) {
int duration = -1;
//如果文件不存在就返回-1
File file = new File(filePath);
if (!file.exists())
return duration;
//如果文件存在但是是流媒体直播的内容则也会返回-1
MediaPlayer player = new MediaPlayer();
try {
player.setDataSource(filePath);
player.prepare();
duration = player.getDuration();
player.reset();
player.release();
} catch (IOException e) {
e.printStackTrace();
}
return duration;
}
public static String durationToStr(int duration) {
//如果传进来的时长为-1则返回代表没有内容的字符串"..:.."
if (-1 == duration)
return "..:..";
//时长不为1的话,则按"分:秒"的字符串形式组合字符串传出
StringBuilder builder = new StringBuilder();
float sumSecond = duration / 1000;
int minute = (int) (sumSecond / 60);
int second = (int) (sumSecond % 60);
builder.append(minute).append(":").append(second);
return builder.toString();
}
}
用的话,就这么用
record= (SoundRecord) findViewById(R.id.record);
record.setFilePath(Environment.getExternalStorageDirectory().getPath()+
File.separatorChar+"123"+".mp3");
也不要忘了添加权限
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.VIBRATE" />这个是振动器的权限