本文主要记录实际开发需要自定义相机页面功能的实现并根据实际需求自己整理的一套逻辑和代码,如有侵权,请联系删除~
页面大概这个样子,有点丑~~可以根据需求改
下面是具体的实现方式:
public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback{
private Camera camera = null;
private SurfaceHolder surfaceHolder = null;
public MySurfaceView(Context context, Camera camera) {
super(context);
this.camera = camera;
surfaceHolder = getHolder();
surfaceHolder.addCallback(this);
surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
public MySurfaceView(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
try{
//开始预览
camera.setPreviewDisplay(surfaceHolder);
camera.startPreview();
}catch(Exception e){
e.printStackTrace();
}
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
//根本没有可处理的SurfaceView
if (surfaceHolder.getSurface() == null){
return ;
}
//先停止Camera的预览
try{
camera.stopPreview();
}catch(Exception e){
e.printStackTrace();
}
//重新开启Camera的预览功能
try{
camera.setPreviewDisplay(surfaceHolder);
camera.startPreview();
}catch(Exception e){
e.printStackTrace();
}
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
}
public class CameraActivity extends AppCompatActivity {
private ImageView iv_camera_capture = null;
private Button btn_camera_cancel = null;
private ImageView iv_camera_flash_light = null;
private Camera camera = Camera.open();
private MySurfaceView mySurfaceView = null;
private byte[] buffer = null;
private final int TYPE_FILE_IMAGE = 1;
private final int TYPE_FILE_VEDIO = 2;
private int openFlashLight = 0;
public String CUTTING_IMAGE_NAME = "PhotoCopy.jpg";
private static final int REQUEST_IMAGE_CUTTING = 2;
private Camera.PictureCallback pictureCallback = new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
if (data == null) {
} else {
}
buffer = new byte[data.length];
buffer = data.clone();
//保存图片
saveImageToFile();
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_camera);
iv_camera_capture = (ImageView) findViewById(R.id.camera_capture);
iv_camera_flash_light = (ImageView) findViewById(R.id.camera_flash_light);
btn_camera_cancel = (Button) findViewById(R.id.camera_cancel);
iv_camera_capture.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
camera.takePicture(null, null, pictureCallback);
}
});
iv_camera_flash_light.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (openFlashLight == 1) {
closeFlashLight();
openFlashLight = 0;
iv_camera_flash_light.setImageResource(R.mipmap.flash_light_open);
} else if (openFlashLight == 0) {
openFlashLight = 1;
openFlashLight();
iv_camera_flash_light.setImageResource(R.mipmap.flash_light_close);
}
}
});
btn_camera_cancel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
}
@Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
camera.release();
camera = null;
}
@Override
protected void onResume() {
super.onResume();
if (camera == null) {
camera = getCameraInstance();
}
//必须放在onResume中,不然会出现Home键之后,再回到该APP,黑屏
mySurfaceView = new MySurfaceView(getApplicationContext(), camera);
FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);
preview.addView(mySurfaceView);
if (getResources().getConfiguration().orientation != Configuration.ORIENTATION_LANDSCAPE) {
camera.setDisplayOrientation(90);
} else {//如果是横屏
camera.setDisplayOrientation(0);
}
//解决方向问题
IOrientationEventListener orientationEventListener = new IOrientationEventListener(this);
mySurfaceView.getHolder().setKeepScreenOn(true);//屏幕常亮
mySurfaceView.getHolder().addCallback(new SurfaceHolder.Callback() {
//当SurfaceHolder被创建的时候回调
@Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
orientationEventListener.enable();
//设置相机的参数
Camera.Parameters parameters = camera.getParameters();
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
List sizeList = parameters.getSupportedPreviewSizes();//获取所有支持的camera尺寸
Camera.Size optionSize = getOptimalPreviewSize(sizeList, mySurfaceView.getHeight(), mySurfaceView.getWidth());//获取一个最为适配的camera.size
parameters.setPreviewSize(optionSize.width, optionSize.height);//把camera.size赋值到parameters
camera.setParameters(parameters);
camera.cancelAutoFocus();
}
//当SurfaceHolder的尺寸发生变化的时候被回调
@Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
}
//当SurfaceHolder被销毁的时候回调
@Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
orientationEventListener.disable();
}
});
}
/*得到一相机对象*/
private Camera getCameraInstance() {
Camera camera = null;
try {
camera = camera.open();
} catch (Exception e) {
e.printStackTrace();
}
return camera;
}
//-----------------------保存图片---------------------------------------
private void saveImageToFile() {
File file = getOutFile(TYPE_FILE_IMAGE);
if (file == null) {
Toast.makeText(getApplicationContext(), "文件创建失败,请检查SD卡读写权限", Toast.LENGTH_SHORT).show();
return;
}
Log.i("MyPicture", "自定义相机图片路径:" + file.getPath());
Toast.makeText(getApplicationContext(), "图片保存路径:" + file.getPath(), Toast.LENGTH_SHORT).show();
if (buffer == null) {
Log.i("MyPicture", "自定义相机Buffer: null");
} else {
try {
FileOutputStream fos = new FileOutputStream(file);
fos.write(buffer);
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
startPhotoZoom();
}
//-----------------------生成Uri---------------------------------------
//得到输出文件的URI ***这里的fileProvider为了适配android9 不会的小伙伴自行百度***
private Uri getOutFileUri(int fileType) {
return FileProvider.getUriForFile(this, "com.xxx.fileProvider", getOutFile(fileType));
}
//生成输出文件
private File getOutFile(int fileType) {
String storageState = Environment.getExternalStorageState();
if (Environment.MEDIA_REMOVED.equals(storageState)) {
Toast.makeText(getApplicationContext(), "oh,no, SD卡不存在", Toast.LENGTH_SHORT).show();
return null;
}
File mediaStorageDir = new File(Environment
.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)
, "MyPictures");
if (!mediaStorageDir.exists()) {
if (!mediaStorageDir.mkdirs()) {
Log.i("MyPictures", "创建图片存储路径目录失败");
Log.i("MyPictures", "mediaStorageDir : " + mediaStorageDir.getPath());
return null;
}
}
File file = new File(getFilePath(mediaStorageDir, fileType));
return file;
}
//生成输出文件路径
private String getFilePath(File mediaStorageDir, int fileType) {
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss")
.format(new Date());
String filePath = mediaStorageDir.getPath() + File.separator;
if (fileType == TYPE_FILE_IMAGE) {
filePath += ("IMG_" + timeStamp + ".jpg");
} else if (fileType == TYPE_FILE_VEDIO) {
filePath += ("VIDEO_" + timeStamp + ".mp4");
} else {
return null;
}
return filePath;
}
/**
* 解决预览变形问题
*
* @param sizes
* @param w
* @param h
* @return
*/
private Camera.Size getOptimalPreviewSize(List sizes, int w, int h) {
final double ASPECT_TOLERANCE = 0.1;
double targetRatio = (double) w / h;
if (sizes == null) return null;
Camera.Size optimalSize = null;
double minDiff = Double.MAX_VALUE;
int targetHeight = h;
// Try to find an size match aspect ratio and size
for (Camera.Size size : sizes) {
double ratio = (double) size.width / size.height;
if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue;
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
// Cannot find the one match the aspect ratio, ignore the requirement
if (optimalSize == null) {
minDiff = Double.MAX_VALUE;
for (Camera.Size size : sizes) {
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
}
return optimalSize;
}
public class IOrientationEventListener extends OrientationEventListener {
public IOrientationEventListener(Context context) {
super(context);
}
@Override
public void onOrientationChanged(int orientation) {
if (ORIENTATION_UNKNOWN == orientation) {
return;
}
Camera.CameraInfo info = new Camera.CameraInfo();
Camera.getCameraInfo(0, info);
orientation = (orientation + 45) / 90 * 90;
int rotation = 0;
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
rotation = (info.orientation - orientation + 360) % 360;
} else {
rotation = (info.orientation + orientation) % 360;
}
Log.e("TAG", "orientation: " + orientation);
if (null != camera) {
Camera.Parameters parameters = camera.getParameters();
parameters.setRotation(rotation);
camera.setParameters(parameters);
}
}
}
/**
* 启动系统裁剪
*/
private void startPhotoZoom() {
Uri uri = getOutFileUri(TYPE_FILE_IMAGE);
//保存裁剪后的图片
File cropFile = new File(Environment.getExternalStorageDirectory().toString() + "/yourname", CUTTING_IMAGE_NAME);
try {
if (cropFile.exists()) {
cropFile.delete();
}
} catch (Exception e) {
e.printStackTrace();
}
Uri cropUri;
cropUri = Uri.fromFile(cropFile);
Intent intent = new Intent("com.android.camera.action.CROP");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
//添加这一句表示对目标应用临时授权该Uri所代表的文件
//需要加上这两句话 : uri 权限
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
}
intent.setDataAndType(uri, "image/*");
intent.putExtra("crop", "true");
// intent.putExtra("aspectX", 1); // 裁剪框比例
// intent.putExtra("aspectY", 1);
// intent.putExtra("outputX", 500); // 输出图片大小
// intent.putExtra("outputY", 500);
intent.putExtra("scale", true);
intent.putExtra("return-data", false);
intent.putExtra(MediaStore.EXTRA_OUTPUT, cropUri);
intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
intent.putExtra("noFaceDetection", true); // no face detection
startActivityForResult(intent, REQUEST_IMAGE_CUTTING);
}
/**
* 打开闪光灯
*/
public void openFlashLight() {
if (camera == null) {
return;
}
Camera.Parameters parameter = camera.getParameters();
parameter.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
camera.setParameters(parameter);
}
/**
* 关闭闪光灯
*/
public void closeFlashLight() {
if (camera == null) {
return;
}
Camera.Parameters parameter = camera.getParameters();
parameter.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
camera.setParameters(parameter);
}
//将截取后的照片返回
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_IMAGE_CUTTING) {
File pictureFile1 = new File(Environment.getExternalStorageDirectory().toString() + "/yourname", CUTTING_IMAGE_NAME);
String imgPath = pictureFile1.getAbsolutePath();
Intent intent = new Intent();
intent.putExtra("imgPath", imgPath);
setResult(RESULT_OK,intent);
finish();
}
}
}