本文介绍 Android7 图片相册裁剪适配教程

Android7 图片相册裁剪适配教程

本文由在当地较为英俊的男子金天大神原创,版权所有,欢迎转载,但请保留这段版权信息,多谢合作,有任何疑问欢迎通过微信联系我交流:jintianiloveu

Android7 适配问题

ok, 新博客的第一篇比较正式的笔记。闲话不多说,本篇博客记录Android7,图片剪切适配的蛋疼问题。首先大家必须要明白,在安卓7中,图片不在是那么操作的了,文件不再是那么简单的操作了,多了一个FileProvider的东西,在以前我们从相册获取一张图片并裁剪可能非常简单和随意:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
public void chooseAvatar() {
Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
intent.setType("image/*");
startActivityForResult(intent, CODE_PHOTO);
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
// TODO Auto-generated method stub
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode){
case CODE_CANCEL:
Toast.makeText(getActivity(), "取消了相册选择", Toast.LENGTH_SHORT).show();
case CODE_PHOTO:
if (data != null) {
Uri uri = data.getData();
DebugHelper.LogMessage("step 2, start zoom image", "crop and choose photo");
startPhotoZoom(uri);
}
break;
case CODE_RESULT:{
Uri inputUri = FileProvider.getUriForFile(getActivity(), "com.ouman.luoliluoli.fileprovider", mCropFile);
Bitmap bitmap = null;
try {
bitmap = BitmapFactory.decodeStream(getActivity().getContentResolver().openInputStream(inputUri));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
DebugHelper.LogMessage("step 4, get result and set cropped image.", "crop and choose photo");
avatar.setImageBitmap(bitmap);
avatarImageFile = mCropFile;
break;
}
}
}
public void startPhotoZoom(Uri inputUri) {
if (inputUri == null) {
Log.e("error","The uri is not exist.");
return;
}
Intent intent = new Intent("com.android.camera.action.CROP");
Uri outPutUri = Uri.fromFile(mCropFile);
if (Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
//这个方法是处理4.4以上图片返回的Uri对象不同的处理方法
String url = FileHelper.getRealPathFromURI(getActivity(), inputUri);
intent.setDataAndType(Uri.fromFile(new File(url)), "image/*");
} else {
intent.setDataAndType(inputUri, "image/*");
}
intent.putExtra(MediaStore.EXTRA_OUTPUT, outPutUri);
intent.putExtra("crop", "true");
// aspectX aspectY 是宽高的比例
intent.putExtra("aspectX", 1);
intent.putExtra("aspectY", 1);
// outputX outputY 是裁剪图片宽高
intent.putExtra("outputX", 250);
intent.putExtra("outputY", 250);
intent.putExtra("return-data", false);
intent.putExtra("noFaceDetection", false);
intent.putExtra("outputFormat", "JPEG");
DebugHelper.LogMessage("step 3, start return result back", "crop and choose photo");
startActivityForResult(intent, CODE_RESULT);
}

我这里并没有修改适配后的代码,总之,在FileProvider之前,获取图片并裁剪比较简单。在android7以后问题也没有变复杂,只不过是不能直接从File中获取Uri,从而无法ContentResolver去获取二进制的数据。那么如何才能去适配呢?

要修改的地方并不多

其实要适配Android7 要修改的地方并不多,甚至说只需要几行代码即可。我看网上很多人说要修改manifest,要修改xml中的file_path.xml,我测试了其实完全没有必要。当然为了保险起见,我们还是在manifest中添加一下权限:

1
2
3
4
5
6
7
8
9
10
<!-- 适配android7 -->
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.ouman.luoliluoli.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>

这里的 com.ouman.luoliluoli.fileprovider可以修改成你的。任何名字都可以,不过一半是包名加provider来命名。最后,我们需要处理的地方加上 FileProvider.getUriForFile(getActivity(), “com.ouman.luoliluoli.fileprovider”, mCropFile); 这个方法,来从File获取Uri。

我总结了一个代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
// variables we need for Android7 image crop
private static final int CODE_PHOTO = 1115;
private static final int CODE_RESULT = 1118;
private static final int CODE_CANCEL = 5556;
String path = Environment.getExternalStorageDirectory()+"/images/";
File mCameraFile = new File(path, "photo.jpg");//照相机的File对象
File mCropFile = new File(path, "avatar.jpg");//裁剪后的File对象
/**
* Basic steps for setting avatar with crop image
* Step 1: Start a intent for PHOTO, this step should be different in android7
* Step 2: onActivityResult received photo request, start zoom image
* Step 3: in startZoomImage it will using gallery to crop image, and then send result code
* Step 4: in onActivityResult method received the cropped image and set it.
*/
public void chooseAvatar() {
// check parent dir is exist or not
if (!mCameraFile.getParentFile().exists()) {
mCameraFile.getParentFile().mkdirs();
}
Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
intent.setType("image/*");
startActivityForResult(intent, CODE_PHOTO);
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
// TODO Auto-generated method stub
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode){
case CODE_CANCEL:
Toast.makeText(getActivity(), "取消了相册选择", Toast.LENGTH_SHORT).show();
case CODE_PHOTO:
if (data != null) {
Uri uri = data.getData();
DebugHelper.LogMessage("step 2, start zoom image", "crop and choose photo");
startPhotoZoom(uri);
}
break;
case CODE_RESULT:{
Uri inputUri = FileProvider.getUriForFile(getActivity(), "com.ouman.luoliluoli.fileprovider", mCropFile);
Bitmap bitmap = null;
try {
bitmap = BitmapFactory.decodeStream(getActivity().getContentResolver().openInputStream(inputUri));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
DebugHelper.LogMessage("step 4, get result and set cropped image.", "crop and choose photo");
avatar.setImageBitmap(bitmap);
avatarImageFile = mCropFile;
break;
}
}
}
public void startPhotoZoom(Uri inputUri) {
if (inputUri == null) {
Log.e("error","The uri is not exist.");
return;
}
Intent intent = new Intent("com.android.camera.action.CROP");
//sdk>=24
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
Uri outPutUri = Uri.fromFile(mCropFile);
intent.setDataAndType(inputUri, "image/*");
intent.putExtra(MediaStore.EXTRA_OUTPUT, outPutUri);
intent.addFlags(FLAG_GRANT_READ_URI_PERMISSION);
intent.addFlags(FLAG_GRANT_WRITE_URI_PERMISSION);
} else {
Uri outPutUri = Uri.fromFile(mCropFile);
if (Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
//这个方法是处理4.4以上图片返回的Uri对象不同的处理方法
String url = FileHelper.getRealPathFromURI(getActivity(), inputUri);
intent.setDataAndType(Uri.fromFile(new File(url)), "image/*");
} else {
intent.setDataAndType(inputUri, "image/*");
}
intent.putExtra(MediaStore.EXTRA_OUTPUT, outPutUri);
}
intent.putExtra("crop", "true");
// aspectX aspectY 是宽高的比例
intent.putExtra("aspectX", 1);
intent.putExtra("aspectY", 1);
// outputX outputY 是裁剪图片宽高
intent.putExtra("outputX", 250);
intent.putExtra("outputY", 250);
intent.putExtra("return-data", false);
intent.putExtra("noFaceDetection", false);
intent.putExtra("outputFormat", "JPEG");
DebugHelper.LogMessage("step 3, start return result back", "crop and choose photo");
startActivityForResult(intent, CODE_RESULT);
}

上述代码,变量加载类里面,几乎不需要修改其他方法,只需要在onActivityResult里面的RESULT CODE里面获取到图片,执行你的逻辑即可。

下期预告

本次老司机列车到此结束,如果大家对本文由任何疑问,欢迎通过渠道联系我。下一篇我们将release 萝莉萝莉第二版本!!