前提:很久没有更新了,今天就为大家带来一个画布和SurfaceView的使用吧。(附源码资源)
需求:录制音频时有时候为了增加与用户的体验,我们需要增加与用户的交互,于是就有了录音动画。如下图
)
分析:录音动画有很多种,比如话筒式的,如微信语音和QQ语音,相对于简单一些,只需几张图片根据音量大小来回切换,这里就不多说了。还有就是类似于心电图,根据音量大小实现及时画出波形图,而这篇文章就能解决以上需求,好了,废话不多说,直接上代码。
首先我们需要建立一个简单的录音界面,如图
activity_test_surface_view.xml如下
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin" >
<SurfaceView
android:id="@+id/record_surfaceView"
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_gravity="center_horizontal"
android:background="@color/acoustic_wave_bg" />
<Button
android:layout_below="@id/record_surfaceView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="录音"
android:onClick="Record"
/>
</RelativeLayout>
接下来就是代码的实现了,首先获取视图和初始化画笔,代码如下
// 初始化视图
private void initView() {
sfv = (SurfaceView) findViewById(R.id.record_surfaceView);
sfv.setZOrderOnTop(true);
sfv.getHolder().setFormat(PixelFormat.TRANSLUCENT);
}
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test_surface_view);
initView();
// 初始化画笔
mPaint = new Paint();
mPaint.setColor(getResources().getColor(R.color.maincolor));// 画笔为主色调
mPaint.setStrokeWidth(4);// 设置画笔粗细
}
做完这俩件事后就是录音的点击事件,具体可以查看以下代码,代码注释也很详细,如有不懂,可留言,我会及时回复
public void Record(View view) {
baseLine = sfv.getHeight() / 2;
if (mediarecord == null) {
//判断文件是否存在,如果存在则删除
File file = new File("mnt/sdcard/a123" + ".m4a");
if (file.exists()) {
file.delete();
}
//初始化<span style="font-family: Arial, Helvetica, sans-serif;">MediaRecorder</span>
mediarecord = new MediaRecorder();
//设置<span style="font-family: Arial, Helvetica, sans-serif;">MediaRecorder的属性</span>
mediarecord.setAudioSource(MediaRecorder.AudioSource.MIC);
mediarecord.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
mediarecord.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
mediarecord.setOutputFile("mnt/sdcard/a123" + ".m4a");
try {//准备
mediarecord.prepare();
} catch (IOException e) {
Log.e("iii", "prepare() failed");
}
//开始录制
mediarecord.start();
//开启画笔线程每0.2绘制一次
sfvtimer = new Timer();
sfvtimer.schedule(new TimerTask() {
@Override
public void run() {
Message message = new Message();
message.what = 1;
mHandler.sendMessage(message);
}
}, 0, 200);
// 录音
} else {
if (mediarecord != null) {
mediarecord.stop();
mediarecord.reset();
mediarecord.release();
mediarecord = null;
sfvtimer.cancel();
sfvtimer = null;
}
}
绘制线程代码如下
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
updateMicStatus();
}
};
updateMicStatus()方法如下:
if (mediarecord != null) {
double ratio = (double) mediarecord.getMaxAmplitude() / BASE;
int db = 0;// 分贝
if (ratio > 1)
db = (int) (20 * Math.log10(ratio)) - 50;
if (db < 0)
db = 0;
x.add(-db);//保存音频分贝大小,根据X里的值绘制一段完整的波浪线
if (x.size() > sfv.getWidth() / divider) {
x.remove(0);//如果长达超出了屏幕宽度则删除第一个数据
}
SimpleDraw(x, baseLine);
}
绘制画板如下:
if (rateY == 0) {
rateY = 200 / sfv.getHeight();
baseLine = sfv.getHeight() / 2;
}
Canvas canvas = sfv.getHolder().lockCanvas(
new Rect(0, 0, sfv.getWidth(), sfv.getHeight()));// 关键:获取画布
canvas.drawColor(getResources().getColor(R.color.acoustic_wave_bg));// 清除背景
int start = sfv.getWidth() - buf.size() * divider;
int py = baseLine;
if (buf.size() > 0)
py += buf.get(0) / rateY;
int y;
canvas.drawLine(0, baseLine, start - divider, baseLine, mPaint);
for (int i = 0; i < buf.size(); i++) {
y = buf.get(i) / rateY + baseLine;// 调节缩小比例,调节基准线
canvas.drawLine(start + (i - 1) * divider, py, start + i * divider,
y, mPaint);
py = y;
}
sfv.getHolder().unlockCanvasAndPost(canvas);// 解锁画布,提交画好的图像
完成到这里就可以实现录音心电图了,效果图如下
不懂得可以留言或者自己下载资源慢慢研究,如有不足,希望大家指出,共同讨论,进步