android拍照、图库与裁剪
16lz
2021-01-26
一、前言
好多APP都有上传图片的功能,无聊是调起相册还是拍照,都必须要在activity的onActivityResult回调方法处理,实现起来比较繁琐。至此对其进一步封装。使用起来更加简单。
二、直接上源码:
GitHub源码
1、首先创建一个PicOptions,作用是配置相关信息
public class PicOptions { private boolean isCrop;//是否裁剪 private int cropWidth;//裁剪宽度 private int cropHeight;//裁剪高度 private String providerAuthority;//7.0以上访问sdcard需要用到 private File cacheFile;//缓存文件 private PicOptions(Builder builder) { isCrop = builder.isCrop; cropWidth = builder.cropWidth; cropHeight = builder.cropHeight; providerAuthority = builder.providerAuthority; cacheFile = builder.cacheFile; } public boolean isCrop() { return isCrop; } public int getCropWidth() { return cropWidth; } public int getCropHeight() { return cropHeight; } public String getProviderAuthority() { return providerAuthority; } public File getCacheFile() { return cacheFile; } public static Builder beginBuilder() { return new Builder(); } public static class Builder { private boolean isCrop = false; private int cropWidth = 0; private int cropHeight = 0; private String providerAuthority; private File cacheFile; public Builder setCrop(boolean crop) { isCrop = crop; return this; } public Builder setCropWidth(int cropWidth) { this.cropWidth = cropWidth; return this; } public Builder setCropHeight(int cropHeight) { this.cropHeight = cropHeight; return this; } public Builder setProviderAuthority(String providerAuthority) { this.providerAuthority = providerAuthority; return this; } public Builder setCacheFile(File cacheFile) { this.cacheFile = cacheFile; return this; } public PicOptions build() { if (this.cacheFile == null) { throw new IllegalArgumentException("cacheFile no found..."); } return new PicOptions(this); } }}
2、回调接口PicListener
public interface PicListener { void onTakePicSuccess(Uri uri);//成功 void onTakePicFail();//失败}
3、管理器PicManager
public class PicManager { private final String TAG = "PicManager"; private final int REQUEST_CODE_CAMERA = 1009;//拍照 private final int REQUEST_CODE_PICTURE = 1008;//相册 private final int REQUEST_CODE_CUT_PIC = 1007;//裁剪 private final String REQUEST_TYPE = "requestType"; private PicOptions picOptions; private PicListener listener; public PicManager setPicOptions(PicOptions picOptions) { this.picOptions = picOptions; return this; } public PicManager setListener(PicListener listener) { this.listener = listener; return this; } public void takeCamera(Context context) { startPicActivity(context, REQUEST_CODE_CAMERA); } public void takePhotoAlbum(Context context) { startPicActivity(context, REQUEST_CODE_PICTURE); } private void startPicActivity(Context context, int type) { Intent intent = new Intent(context, PicActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.putExtra(REQUEST_TYPE, type); context.startActivity(intent); } public void behavior(Activity activity, Intent intent, Bundle savedInstanceState) { if (intent == null) { YLogUtil.INSTANCE.eTag(TAG, "behavior intent is null"); onDestroy(activity); return; } if (intent.getExtras() == null) { YLogUtil.INSTANCE.eTag(TAG, "behavior extras is null"); onDestroy(activity); return; } if (savedInstanceState == null) { int requestType = intent.getExtras().getInt(REQUEST_TYPE); if (requestType == REQUEST_CODE_CAMERA) { executeCamera(activity); } else if (requestType == REQUEST_CODE_PICTURE) { executePhotoAlbum(activity); } } } private void executeCamera(Activity context) { String providerAuthority = context.getPackageName() + ".FileProvider"; if (null != picOptions.getProviderAuthority() && !picOptions.getProviderAuthority().isEmpty()) { providerAuthority = picOptions.getProviderAuthority(); } Uri imageUri; Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); // 判断版本大于等于7.0 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { try { imageUri = FileProvider.getUriForFile(context, providerAuthority, picOptions.getCacheFile()); } catch (Exception e) { e.printStackTrace(); imageUri = Uri.fromFile(picOptions.getCacheFile()); } // 给目标应用一个临时授权 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); } else { imageUri = Uri.fromFile(picOptions.getCacheFile()); } // 指定调用相机拍照后照片的储存路径 intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri); context.startActivityForResult(intent, REQUEST_CODE_CAMERA); } private void executePhotoAlbum(Activity context) { Intent intent = new Intent(Intent.ACTION_PICK, null); intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*"); context.startActivityForResult(intent, REQUEST_CODE_PICTURE); } private void crop(Activity context, Uri uri) { YLogUtil.INSTANCE.iFormatTag(TAG, "crop uri:%s", uri); Intent intent = new Intent("com.android.camera.action.CROP"); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); } intent.setDataAndType(uri, "image/*"); // crop为true是设置在开启的intent中设置显示的view可以剪裁 intent.putExtra("crop", "true"); // aspectX aspectY 是宽高的比例 intent.putExtra("aspectX", 1); intent.putExtra("aspectY", 1); // outputX,outputY 是剪裁图片的宽高 intent.putExtra("outputX", picOptions.getCropWidth()); intent.putExtra("outputY", picOptions.getCropHeight()); intent.putExtra("return-data", false); // intent.putExtra(MediaStore.EXTRA_OUTPUT, intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(picOptions.getCacheFile())); intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString()); intent.putExtra("noFaceDetection", true); // no face detection context.startActivityForResult(intent, REQUEST_CODE_CUT_PIC); } public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) { if (listener == null || (requestCode != REQUEST_CODE_CAMERA && requestCode != REQUEST_CODE_PICTURE && requestCode != REQUEST_CODE_CUT_PIC)) { YLogUtil.INSTANCE.eTag(TAG, "onActivityResult Unknown requestCode or listener is null"); onDestroy(activity); return; } if (resultCode != android.app.Activity.RESULT_OK) { YLogUtil.INSTANCE.eTag(TAG, "onActivityResult--cancel--resultCode", resultCode); onDestroy(activity); return; } switch (requestCode) { case REQUEST_CODE_CAMERA: YLogUtil.INSTANCE.iTag(TAG, "onActivityResult camera"); scanFile(activity, picOptions.getCacheFile().getAbsolutePath(), picOptions.isCrop()); break; case REQUEST_CODE_PICTURE: if (data == null || data.getData() == null) { YLogUtil.INSTANCE.eTag(TAG, "onActivityResult picture data is null "); listener.onTakePicFail(); onDestroy(activity); return; } YLogUtil.INSTANCE.iTag(TAG, "onActivityResult picture"); if (picOptions.isCrop()) { crop(activity, data.getData()); } else { YLogUtil.INSTANCE.iFormatTag(TAG, "onActivityResult picture callback uri:%s", data.getData()); listener.onTakePicSuccess(data.getData()); onDestroy(activity); } break; case REQUEST_CODE_CUT_PIC: YLogUtil.INSTANCE.iTag(TAG, "onActivityResult crop"); scanFile(activity, picOptions.getCacheFile().getAbsolutePath(), false); break; } } private void scanFile(final Activity activity, String path, final boolean isCrop) { MediaScannerConnection.scanFile(activity, new String[]{path}, new String[]{"image/jpeg"}, new MediaScannerConnection.OnScanCompletedListener() { @Override public void onScanCompleted(String path, final Uri uri) { HandlerUtil.INSTANCE.runOnUiThread(new Runnable() { @Override public void run() { if (isCrop) { crop(activity, uri); } else { YLogUtil.INSTANCE.iFormatTag(TAG, "scanFile camera or crop callback uri:%s", uri); listener.onTakePicSuccess(uri); onDestroy(activity); } } }); } }); } /** * 摧毁本库的 PicActivity */ private void onDestroy(Activity activity) { if (activity != null) { activity.finish(); } }}
4、Pic
public class Pic { private PicManager picManager; private Pic() { picManager = new PicManager(); } public static synchronized Pic getInstance() { return PicHolder.instance; } private static class PicHolder { private static final Pic instance = new Pic(); } public PicManager getPicManager() { return picManager; }}
5、真正调起拍照或相册的activity,PicActivity
public class PicActivity extends AppCompatActivity { @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); //不接受触摸屏事件 getWindow().addFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE); Pic.getInstance().getPicManager().behavior(this, getIntent(), savedInstanceState); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); Pic.getInstance().getPicManager().onActivityResult(this, requestCode, resultCode, data); }}
6、注册PicActivity到manifest
7、示例:
调起摄像头
Pic.getInstance().picManager.setPicOptions(getPicOptions()).setListener(listener).takeCamera(context)
调起相册
Pic.getInstance().picManager.setPicOptions(getPicOptions()).setListener(listener).takePhotoAlbum(context)
private PicOptions getPicOptions(){ File cacheFile = File(FileUtils.getSdcardPath(), TimeUtil.nowTimeStr + ".jpg"); return PicOptions.beginBuilder() .setCacheFile(cacheFile) .setCrop(checkBox.isChecked) .setCropHeight(200) .setCropWidth(200) .build(); }
更多相关文章
- Android(安卓)studio使用相机拍照,保存并显示一坨屎一样的照片
- android上层得到底层数据的回调机制
- Android、H5 单独调起拍照与摄像
- Android自定义照相机实现 拍照 录像
- Android高仿微信相册选择器 多图片选择器、拍照
- android拍照获得图片及获得图片后剪切设置到ImageView
- android 拍照截取 部分照片(拍照截取行驶证)
- Android保存图片到系统相册并更新
- 【转】Android大图片裁剪终极解决方案 原理分析