引用
1、Android7.0 頭像 拍照、照片裁剪
2、聯合使用:Android 仿IOS的PopupWindow和通用BasePopupWindow搭建
截圖
實現
1、功能步驟
- 1.1、相機和相冊使用到的權限
- 1.2、打開相機、打開相冊
- 1.3、相機拍照回調、相冊選取回調
- 1.4、兩種不同方式回調後的uri使用並開啓剪裁
- 1.5、剪裁圖片回調、展示圖片(各種樣式)
- 1.6、其他注意:android 7.0 後的共享文件FileProvider配置等
2、工具類
- 2.1、此工具類不一定符合所有業務,可自行擴展或者弄成接口類來完成各種功能
- 2.2、使用相機:注意android 7.0的fileprovider來獲取uri,完成拍照存儲
- 2.3、使用相冊:注意ACTION_PICK和ACTION_GET_CONTENT的區別,並在不同api下返回的uri值不一樣導致“無法加載圖片”的問題,代碼中寫了註釋
- 2.4、相機圖片剪裁:注意要加上intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);作爲圖片來源加載在剪切圖中
- 2.5、相冊圖片剪裁:不用加【2.4】內容
- 2.6、剪裁輸出源:可直接intent.putExtra("return-data", true);返回直接是bitmap有可能導致oom,還是設置false,然後靠uri來指向輸出源比較好
/**
* Created by wujn on 2018/10/31.
* Version : v1.0
* Function: crop photo by camera or album
*/
public class CropPhotoHelper {
private Activity instance;
// 裁剪後圖片的寬(X)和高(Y),320 X 320的正方形。
private static int output_X = 480;
private static int output_Y = 480;
private String localUserImgName ; //原始拍照圖片
private String localUserImgPath;
private Uri takePhotoUri; //拍照的uri
private String localUserCropImgName; //最後的剪裁圖片
private String localUserCropImgPath;
private Uri localUserIconUri; //用戶頭像圖片uri
private String parentDir; //父目錄
public CropPhotoHelper(Activity instance, String localUserImgName, String localUserCropImgName, String parentDir){
this.instance = instance;
this.localUserImgName = localUserImgName;
this.localUserImgPath = parentDir + localUserImgName;
this.localUserCropImgName = localUserCropImgName;
this.localUserCropImgPath = parentDir + localUserCropImgName;
this.parentDir = parentDir;
}
/**
* 拍照
* uri = content://.fileprovider/external_storage_root/xxx/xxx.jpg
* */
public void takePhoto(boolean isDeleteOld, int requestCode){
FileUtil.mkDir(parentDir);
File tmpFile=new File(localUserImgPath); //固定的,用戶圖片
//刪除舊的
if (isDeleteOld) {
try {
if (tmpFile.exists()) {
tmpFile.delete();//刪除
}
tmpFile.createNewFile();
} catch (Exception e) {
e.printStackTrace();
}
}
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
takePhotoUri = Uri.fromFile(tmpFile);
}else{
takePhotoUri = FileProvider.getUriForFile(instance, Constant.FileProviderValue, tmpFile);
}
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, takePhotoUri);
//intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
//intent.putExtra(MediaStore.Images.Media.ORIENTATION, 0);
//intent.putExtra("aspectX", 4);
//intent.putExtra("aspectY", 3);
//intent.putExtra(MediaStore.EXTRA_SIZE_LIMIT, 120 * 1024);
//intent.putExtra("return-data", true);
instance.startActivityForResult(intent, requestCode);
}
/**
* 打開相冊
* 1、Intent.ACTION_PICK,null :
* uri=content://media/external/images/media/86916
*
* 2、Intent.ACTION_GET_CONTENT :
* (1)<=4.3 : uri 返回的是帶文件路徑的
* (2)>4.3 : uri 返回content://com.android.providers.media.documents/document/image:3951
* 這樣的,沒有路徑,只有圖片編號的uri.這就導致接下來無法根據圖片路徑來裁剪的步驟了.
* */
public void openAlbum(int requestCode){
//method 1
// Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
// intent.setType("image/*");
//method 2
Intent intent = new Intent(Intent.ACTION_PICK);
//intent.setType("image*//*");
intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,"image/*");
instance.startActivityForResult(intent,requestCode);//打開相冊
}
/**
* 從相機拍照的圖片剪裁
* */
public void cropRawByCamera(int requestCode){
LogUtil.i("cropRawByCamera inputUri="+ takePhotoUri.toString());
Intent intent = getCropImgIntent();
//輸入原始圖片:來源於拍照
if(takePhotoUri != null){
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.setDataAndType(takePhotoUri, "image/*");
}
instance.startActivityForResult(intent, requestCode);
}
/**
* 從相冊圖片剪裁
* */
public void cropRawByAlbum(Uri inputUri, int requestCode){
LogUtil.i("cropRawByAlbum inputUri="+ inputUri.toString());
Intent intent = getCropImgIntent();
//輸入原始圖片:來源於相冊
if(inputUri != null){
//intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
intent.setDataAndType(inputUri, "image/*");
}
instance.startActivityForResult(intent, requestCode);
}
/**
* 裁剪原始的圖片意圖
*/
private Intent getCropImgIntent(){
//剪裁action
Intent intent = new Intent("com.android.camera.action.CROP");
// 設置裁剪
intent.putExtra("crop", "true");
// aspectX , aspectY :寬高的比例
intent.putExtra("aspectX", 1);
intent.putExtra("aspectY", 1);
// outputX , outputY : 裁剪圖片寬高
intent.putExtra("outputX", output_X);
intent.putExtra("outputY", output_Y);
intent.putExtra("scale",true);
// 返回類型和文件指向
// return data is bitmap , maybe oom
//intent.putExtra("return-data", true); //返回bitmap
intent.putExtra("return-data", false); //返回uri
//輸出剪裁圖片
File cropFile = new File(localUserCropImgPath);
try {
if (cropFile.exists()){
cropFile.delete();//刪除
}
cropFile.createNewFile();
} catch (Exception e) {
e.printStackTrace();
}
localUserIconUri = Uri.fromFile(cropFile);
if (localUserIconUri != null) {
//intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
intent.putExtra(MediaStore.EXTRA_OUTPUT, localUserIconUri);
}
//取消人臉識別
intent.putExtra("noFaceDetection", true);
//壓縮圖片
intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
return intent;
}
/**
* 獲取剪切後的bitmap
* */
public Bitmap getCropBitmap(){
try {
return BitmapFactory.decodeStream(instance.getContentResolver().openInputStream(localUserIconUri));
} catch (FileNotFoundException e) {
e.printStackTrace();
return null;
}
}
//獲取剪裁後的路徑
public String getLocalUserCropImgPath() {
return localUserCropImgPath;
}
}
3、使用
- 3.1、各種回調請求的code
/**
* 權限訪問請求code
* */
public static final int REQUEST_PERMISSION_CODE = 1;
public static final int REQUEST_PERMISSION_CODE_1 = 2;
/**
* ActivityResult回調的請求code
* */
public static final int REQUEST_TACKPIC_CODE = 10001; //相機
public static final int REQUEST_CHOOSE_PHOTO_CODE = 10002; //相冊
public static final int REQUEST_CROP_IMAGE_CODE = 10003; //剪裁圖片
- 3.2、使用相機和相冊的權限詢問
- 3.3、按照【1】所說的步驟來使用
- 3.4、圖片最後使用了AvatarImageView來加載圖片,這個剪裁圖片加載就不再這裏寫了,可以使用的方法巨多...
//剪裁幫助類
private CropPhotoHelper cropPhotoHelper;
@BindView(R.id.avatar_img) AvatarImageView avatar_img;
@Override
protected void init() {
//剪裁幫助類:原始圖片,剪裁圖片,父目錄
cropPhotoHelper = new CropPhotoHelper(instance,
"img_org.jpg",
"img_crop.jpg",
Constant.IMG_DIR);
}
//拍照取圖
public void OnSelectCamera(View v){
if (EasyPermissions.hasPermissions(instance, permissions_camear)) {
cropPhotoHelper.takePhoto(false, Constant.REQUEST_TACKPIC_CODE);
}else{
EasyPermissions.requestPermissions(instance, "App 運行需要獲取權限",Constant.REQUEST_PERMISSION_CODE, permissions_camear);
}
}
//相冊取圖
public void OnSelectAlbum(View v){
if (EasyPermissions.hasPermissions(instance, permissions_album)) {
cropPhotoHelper.openAlbum(Constant.REQUEST_CHOOSE_PHOTO_CODE);
}else{
EasyPermissions.requestPermissions(instance, "App 運行需要獲取權限",Constant.REQUEST_PERMISSION_CODE_1, permissions_album);
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == RESULT_OK) {
switch (requestCode) {
//拍照回調
case Constant.REQUEST_TACKPIC_CODE:
LogUtil.d("take picture success");
cropPhotoHelper.cropRawByCamera(Constant.REQUEST_CROP_IMAGE_CODE);
break;
//選擇照片回調
case Constant.REQUEST_CHOOSE_PHOTO_CODE:
LogUtil.d("choose picture success");
if (data != null) {
//不同api下獲取相冊圖片的path
//String photoPath = AppUtil.getPhotoPath(instance, data);
cropPhotoHelper.cropRawByAlbum(data.getData(),Constant.REQUEST_CROP_IMAGE_CODE);
} else {
ToastUtil.showShort(instance,"相冊無返回值!");
}
break;
//剪裁完
case Constant.REQUEST_CROP_IMAGE_CODE:
Bitmap bitmap = cropPhotoHelper.getCropBitmap();
if(bitmap != null){
avatar_img.setBitmap(bitmap);
}else{
ToastUtil.showShort(instance,"剪裁失敗!");
}
break;
default:
break;
}
}
}
//=============================================權限部分=====================================================
//相機權限
private String[] permissions_camear = {
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.CAMERA
};
//文件權限
private String[] permissions_album = {
Manifest.permission.WRITE_EXTERNAL_STORAGE
};
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this);
}
@Override
public void onPermissionsGranted(int requestCode, @NonNull List<String> perms) {
LogUtil.i("onPermissionsGranted requestCode="+requestCode);
if(Constant.REQUEST_PERMISSION_CODE == requestCode){
cropPhotoHelper.takePhoto(false, Constant.REQUEST_TACKPIC_CODE);
}
else if(Constant.REQUEST_PERMISSION_CODE_1 == requestCode){
cropPhotoHelper.openAlbum(Constant.REQUEST_CHOOSE_PHOTO_CODE);
}
}
@Override
public void onPermissionsDenied(int requestCode, @NonNull List<String> perms) {
DialogUtil.errorDialog(instance,"拒絕開啓,請前往APP應用設置中打開此權限");
}