这篇博客为大家介绍Android自定义相机,并且实现倒计时拍照功能。
首先自定义拍照会用到SurfaceView控件显示照片的预览区域,以下是布局文件:
activity_main.xml
MainActivity.java
package com.jackie.timercamera;import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.hardware.Camera;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;public class MainActivity extends AppCompatActivity implements SurfaceHolder.Callback,View.OnClickListener, Camera.PictureCallback {private SurfaceView mSurfaceView;private ImageView mIvStart;private TextView mTvCountDown;private SurfaceHolder mHolder;private Camera mCamera;private Handler mHandler = new Handler();private int mCurrentTimer = 10;private boolean mIsSurfaceCreated = false;private boolean mIsTimerRunning = false;private static final int CAMERA_ID = 0; //后置摄像头
// private static final int CAMERA_ID &#61; 1; //前置摄像头private static final String TAG &#61; MainActivity.class.getSimpleName();&#64;Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);initView();initEvent();}&#64;Overrideprotected void onPause() {super.onPause();stopPreview();}private void initView() {mSurfaceView &#61; (SurfaceView) findViewById(R.id.surface_view);mIvStart &#61; (ImageView) findViewById(R.id.start);mTvCountDown &#61; (TextView) findViewById(R.id.count_down);}private void initEvent() {mHolder &#61; mSurfaceView.getHolder();mHolder.addCallback(this);mIvStart.setOnClickListener(this);}&#64;Overridepublic void surfaceCreated(SurfaceHolder holder) {mIsSurfaceCreated &#61; true;}&#64;Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {startPreview();}&#64;Overridepublic void surfaceDestroyed(SurfaceHolder holder) {mIsSurfaceCreated &#61; false;}private void startPreview() {if (mCamera !&#61; null || !mIsSurfaceCreated) {Log.d(TAG, "startPreview will return");return;}mCamera &#61; Camera.open(CAMERA_ID);Camera.Parameters parameters &#61; mCamera.getParameters();int width &#61; getResources().getDisplayMetrics().widthPixels;int height &#61; getResources().getDisplayMetrics().heightPixels;Camera.Size size &#61; getBestPreviewSize(width, height, parameters);if (size !&#61; null) {//设置预览分辨率parameters.setPreviewSize(size.width, size.height);//设置保存图片的大小parameters.setPictureSize(size.width, size.height);}//自动对焦parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);parameters.setPreviewFrameRate(20);//设置相机预览方向mCamera.setDisplayOrientation(90);mCamera.setParameters(parameters);try {mCamera.setPreviewDisplay(mHolder);} catch (Exception e) {Log.d(TAG, e.getMessage());}mCamera.startPreview();}private void stopPreview() {//释放Camera对象if (mCamera !&#61; null) {try {mCamera.setPreviewDisplay(null);mCamera.stopPreview();mCamera.release();mCamera &#61; null;} catch (Exception e) {Log.e(TAG, e.getMessage());}}}private Camera.Size getBestPreviewSize(int width, int height,Camera.Parameters parameters) {Camera.Size result &#61; null;for (Camera.Size size : parameters.getSupportedPreviewSizes()) {if (size.width <&#61; width && size.height <&#61; height) {if (result &#61;&#61; null) {result &#61; size;} else {int resultArea &#61; result.width * result.height;int newArea &#61; size.width * size.height;if (newArea > resultArea) {result &#61; size;}}}}return result;}&#64;Overridepublic void onClick(View v) {switch (v.getId()) {case R.id.start:if (!mIsTimerRunning) {mIsTimerRunning &#61; true;mHandler.post(timerRunnable);}break;}}private Runnable timerRunnable &#61; new Runnable() {&#64;Overridepublic void run() {if (mCurrentTimer > 0) {mTvCountDown.setText(mCurrentTimer &#43; "");mCurrentTimer--;mHandler.postDelayed(timerRunnable, 1000);} else {mTvCountDown.setText("");mCamera.takePicture(null, null, null, MainActivity.this);playSound();mIsTimerRunning &#61; false;mCurrentTimer &#61; 10;}}};&#64;Overridepublic void onPictureTaken(byte[] data, Camera camera) {try {FileOutputStream fos &#61; new FileOutputStream(new File(Environment.getExternalStorageDirectory() &#43; File.separator &#43;System.currentTimeMillis() &#43; ".png"));//旋转角度&#xff0c;保证保存的图片方向是对的Bitmap bitmap &#61; BitmapFactory.decodeByteArray(data, 0, data.length);Matrix matrix &#61; new Matrix();matrix.setRotate(90);bitmap &#61; Bitmap.createBitmap(bitmap, 0, 0,bitmap.getWidth(), bitmap.getHeight(), matrix, true);bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);fos.flush();fos.close();} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}mCamera.startPreview();}/*** 播放系统拍照声音*/public void playSound() {MediaPlayer mediaPlayer &#61; null;AudioManager audioManager &#61; (AudioManager) getSystemService(Context.AUDIO_SERVICE);int volume &#61; audioManager.getStreamVolume( AudioManager.STREAM_NOTIFICATION);if (volume !&#61; 0) {if (mediaPlayer &#61;&#61; null)mediaPlayer &#61; MediaPlayer.create(this, Uri.parse("file:///system/media/audio/ui/camera_click.ogg"));if (mediaPlayer !&#61; null) {mediaPlayer.start();}}}
}
有两点需要注意&#xff1a;对于Camera来说&#xff0c;默认是横屏的&#xff0c;所以预览的时候和图片保存的时候都是横屏的&#xff0c;需要调整角度。
设置相机预览方法&#xff1a;
//设置相机预览方向
mCamera.setDisplayOrientation(90);
保存图片的时候调整角度&#xff1a;
效果图如下&#xff1a;