1.图片路径处理类
public class UriUtil {
@TargetApi(Build.VERSION_CODES.KITKAT)
public static String getPath(final Context context, final Uri uri) {
final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
// DocumentProvider
if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
// ExternalStorageProvider
if (isExternalStorageDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
if ("primary".equalsIgnoreCase(type)) {
return Environment.getExternalStorageDirectory() + "/" + split[1];
}
// TODO handle non-primary volumes
}
// DownloadsProvider
else if (isDownloadsDocument(uri)) {
final String id = DocumentsContract.getDocumentId(uri);
final Uri contentUri = ContentUris.withAppendedId(
Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
return getDataColumn(context, contentUri, null, null);
}
// MediaProvider
else if (isMediaDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
Uri contentUri = null;
if ("image".equals(type)) {
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
} else if ("video".equals(type)) {
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
} else if ("audio".equals(type)) {
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
}
final String selection = "_id=?";
final String[] selectionArgs = new String[]{
split[1]
};
return getDataColumn(context, contentUri, selection, selectionArgs);
}
} else if ("content".equalsIgnoreCase(uri.getScheme())) {
if (isGooglePhotosUri(uri)) {
return uri.getLastPathSegment();
}
return getDataColumn(context, uri, null, null);
} else if ("file".equalsIgnoreCase(uri.getScheme())) {
return uri.getPath();
}
return null;
}
/**
* Get the value of the data column for this Uri. This is useful for
* MediaStore Uris, and other file-based ContentProviders.
*
* @param context The context.
* @param uri The Uri to query.
* @param selection (Optional) Filter used in the query.
* @param selectionArgs (Optional) Selection arguments used in the query.
* @return The value of the _data column, which is typically a file path.
*/
public static String getDataColumn(Context context, Uri uri, String selection,
String[] selectionArgs) {
Cursor cursor = null;
final String column = "_data";
final String[] projection = {
column
};
try {
cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs,
null);
if (cursor != null && cursor.moveToFirst()) {
final int index = cursor.getColumnIndexOrThrow(column);
return cursor.getString(index);
}
} finally {
if (cursor != null) {
cursor.close();
}
}
return null;
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is ExternalStorageProvider.
*/
public static boolean isExternalStorageDocument(Uri uri) {
return "com.android.externalstorage.documents".equals(uri.getAuthority());
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is DownloadsProvider.
*/
public static boolean isDownloadsDocument(Uri uri) {
return "com.android.providers.downloads.documents".equals(uri.getAuthority());
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is MediaProvider.
*/
public static boolean isMediaDocument(Uri uri) {
return "com.android.providers.media.documents".equals(uri.getAuthority());
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is Google Photos.
*/
public static boolean isGooglePhotosUri(Uri uri) {
return "com.google.android.apps.photos.content".equals(uri.getAuthority());
}
}
2.图片选择和裁剪工具类
/**
* 调用android原生图片选择器(包括系统裁剪)
* @author gyq
*/
public class PhotoSelectUtil {
public static final int SELECT_PHOTO = 1;
public static final int CROP_PHOTO = 2;
private Activity activity;
private Uri resultUri = null;
private File cropImageFile = null;
public PhotoSelectUtil(Activity activity) {
this.activity = activity;
}
/***
* 从相册中选取图片
*/
public void pickPhoto() {
try {
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) {
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/*");
activity.startActivityForResult(intent, SELECT_PHOTO);
} else {
//Intent.ACTION_GET_CONTENT 好像没啥区别
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("image/*");
intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");
activity.startActivityForResult(intent, SELECT_PHOTO);
}
} catch (Exception e) {
activity.finish();
}
}
/**
* 在Activity的onActivityResult中调用,此方法后面调用super.onActivityResult(requestCode, resultCode, data);
* @param requestCode
* @param resultCode
* @param intent
* @param cropAspectX 宽高比
* @param cropAspectY
* @param cropOutputX 截图的宽高
* @param cropOutputY
*/
public void handleActivityResult(int requestCode, int resultCode, Intent intent,int cropAspectX,int cropAspectY,int cropOutputX,int cropOutputY) {
if (resultCode == Activity.RESULT_OK) {
switch (requestCode) {
case SELECT_PHOTO:
Uri photoUri = intent.getData();
startPhotoZoom(photoUri, cropAspectX, cropAspectY, cropOutputX, cropOutputY);
break;
case CROP_PHOTO:
refreshSystemAlbum(cropImageFile);
// TODO: 2018/7/19 截图保存在cropImageFile中,可对截图做相应的操作
if (activity instanceof PhotoSelectTestActivity && cropImageFile != null) {
Bitmap bitmap = BitmapFactory.decodeFile(cropImageFile.getAbsolutePath());
if (bitmap != null) {
((PhotoSelectTestActivity) activity).setCropImage(bitmap);
}
}
break;
default:
break;
}
}
}
/**
* 插入到系统相册,通知图库更新
* @param cropImageFile
*/
private void refreshSystemAlbum(File cropImageFile) {
try {
MediaStore.Images.Media.insertImage(activity.getContentResolver(),
cropImageFile.getAbsolutePath(), "CropImage.jpeg", null);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
activity.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE,Uri.fromFile(cropImageFile)));
}
/**
* 选择图片后,获取图片的路径
*/
private String getPicturePath(Uri photoUri) {
String flag = "file";
if (!photoUri.toString().contains(flag)) {
return UriUtil.getPath(activity, photoUri);
} else {
return photoUri.getPath();
}
}
/**
* 调用系统自带截图
* @param photoUri 选择图片后返回的uri
* @param aspectX 裁剪图片的宽高比
* @param aspectY
* @param outputX 裁剪图片的宽高
* @param outputY
*/
private void startPhotoZoom(Uri photoUri, int aspectX, int aspectY, int outputX, int outputY) {
final int VERSION_M = 24;
String picPath = getPicturePath(photoUri);
photoUri = Uri.parse(picPath);
prepareResultUri();
Intent intent = new Intent("com.android.camera.action.CROP");
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
try {
Uri tempUri = null;
//适配android 7.0以上版本
if (Build.VERSION.SDK_INT >= VERSION_M) {
tempUri = FileProvider.getUriForFile(activity, "com.anke.app.activity.fileprovider", new File(picPath));
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
} else {
tempUri = Uri.fromFile(new File(picPath));
}
intent.setDataAndType(tempUri, "image/*");
} catch (Exception e) {
e.printStackTrace();
}
} else {
intent.setDataAndType(photoUri, "image/*");
}
intent.putExtra("crop", "true");
// 图片的输出格式
intent.putExtra("outputFormat", Bitmap.CompressFormat.PNG.toString());
intent.putExtra("aspectX", aspectX);
intent.putExtra("aspectY", aspectY);
intent.putExtra("outputX", outputX);
intent.putExtra("outputY", outputY);
//这里有个坑,如果截的是大图,那么截完后不会执行onActivityResult方法
//intent.putExtra("return-data", true);
// 设置剪切的图片保存位置,注意 resultUri 是由fromFile创建的
intent.putExtra(MediaStore.EXTRA_OUTPUT, resultUri);
activity.startActivityForResult(intent, CROP_PHOTO);
}
/**
* 创建保存截图后的文件路径 resultUri 必须由Uri.fromFile创建,不然会提示无法保存经过裁剪的图片
*/
private void prepareResultUri() {
cropImageFile = new File(DataConstant.CROP_PICTURE_PATH);
if (!cropImageFile.exists()) {
cropImageFile.mkdirs();
}
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.CHINA);
String filename = "IMG_" + dateFormat.format(new Date(System.currentTimeMillis())) + ".png";
cropImageFile = new File(cropImageFile, filename);
resultUri = Uri.fromFile(cropImageFile);
}
}
3.用例
在Activity中的简单调用
4.适配android 7.0
在androidManifest中声明,注意声明的FileProvider不能和其他应用声明的一样
在src/mian/res目录下,注意文件名字跟声明时一致
5.注意需要的权限声明
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />