目前主流app都具有上傳頭像啊,上傳圖片的功能,看起來好簡單的需求,但是其實這里面有一點點不同的地方。先說一下我的思路,因為開發周期的問題,并沒有打算自定義相機與圖片查詢工具,打算采用系統相機和圖片查看工具,最開始我打算調用系統的剪裁并且取得的效果還是不錯的,因為我最開始做的是系統頭像上傳的這個功能,后來我采用同樣的方法做了上傳商品圖片的功能,但是這個時候就暴露了之前的隱患。
我先說一下,安卓系統的默認的機制,Intent觸發Camera程序,拍好照片后,將會返回數據,但是考慮到內存問題,Camera不會將全尺寸的圖像返回給調用的Activity,一般情況下,有可能返回的是縮略圖,比如120*160px。這看起來就像是一個縮略圖一樣了,這樣的效果是讓我們非常不滿意的,因為我們想要上傳的明明是一個高清的圖片,但是這樣我們上傳的竟然是一個特別模糊的圖片啦,所以我們不能采用這種辦法了。
我們的思路:調用系統相機,拍照完將拍完的照片存在sd卡的某一個地方,然后我們調用自己的剪裁工具,不調用系統的剪裁工具了,這樣我們剪裁完的圖片也就是一張高清的圖片了,這樣就完美的解決了所遇到的問題。
順便給大家介紹一款,比較不錯的剪裁工具:ucrop
這款工具,特別的小巧,自定義功能非常強,我在項目中是這樣用的:
public static String startUCrop(Activity activity, String sourceFilePath,
int requestCode, float aspectRatioX, float aspectRatioY) {
Uri sourceUri = Uri.fromFile(new File(sourceFilePath));
File outDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
if (!outDir.exists()) {
outDir.mkdirs();
}
File outFile = new File(outDir, System.currentTimeMillis() + ".jpg");
//裁剪后圖片的絕對路徑
String cameraScalePath = outFile.getAbsolutePath();
Uri destinationUri = Uri.fromFile(outFile);
//初始化,第一個參數:需要裁剪的圖片;第二個參數:裁剪后圖片
UCrop uCrop = UCrop.of(sourceUri, destinationUri);
//初始化UCrop配置
UCrop.Options options = new UCrop.Options();
//設置裁剪圖片可操作的手勢
options.setAllowedGestures(UCropActivity.SCALE, UCropActivity.ROTATE, UCropActivity.ALL);
//是否隱藏底部容器,默認顯示
options.setHideBottomControls(true);
//設置toolbar顏色
options.setToolbarColor(ActivityCompat.getColor(activity, R.color.colorPrimary));
//設置狀態欄顏色
options.setStatusBarColor(ActivityCompat.getColor(activity, R.color.colorPrimary));
//是否能調整裁剪框
options.setFreeStyleCropEnabled(true);
//UCrop配置
uCrop.withOptions(options);
//設置裁剪圖片的寬高比,比如16:9
uCrop.withAspectRatio(aspectRatioX, aspectRatioY);
//uCrop.useSourceImageAspectRatio();
//跳轉裁剪頁面
uCrop.start(activity, requestCode);
return cameraScalePath;
}
看了圖片之后,應該不用我說這個庫有多強大了吧,通過簡單的設置之后,可以輕松的實現圖片的旋轉啊,圖片的縮放啊,和各種實用的操作,特別的實用。
下面展示一下我們調用系統的拍照,和系統的相冊的代碼:
/**
* 啟動手機相冊
*/
private void fromGallery() {
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("image/*");
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File(Environment.getExternalStorageDirectory(), IMAGE_NAME)));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
startActivityForResult(intent, GALLERY_KITKAT_REQUEST);
} else {
startActivityForResult(intent, GALLERY_REQUEST);
}
}
/**
* 啟動手機相機
*/
private void fromCamera() {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (FileUtil.hasSdcard()) {
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File(Environment.getExternalStorageDirectory(), IMAGE_NAME)));
startActivityForResult(intent, CAMERA_REQUEST);
} else {
Log.i("sys", "--lin--> SD not exist");
}
}
//如果我們采取的是,調用相冊中的照片,我們只需要這樣便可以獲取到圖片,并且直接加載到我們的第三方剪裁庫里面。
String url = getPath(ReleaseOrderActivity.this, data.getData());
Log.i("lin", "----lin---- url :" + url);
startUCrop(ReleaseOrderActivity.this, url, 1000, 300, 300);
//如果我們采用的是調用系統的相機的話,采用這種方式便可以獲取到照片,并且加載到我們的剪裁的工具里面啦。
startUCrop(ReleaseOrderActivity.this, Environment.getExternalStorageDirectory() + "/" + IMAGE_NAME, 1000, 300, 300);
當然,上面我們應用到了一個,getPath的方法,當然顧名思義嘛,就是要找到圖片的所在位置,但是怕大家懶得自己寫,在這里我就給出來:
//以下是關鍵,原本uri返回的是file:///...來著的,android4.4返回的是content:///...
@SuppressLint("NewApi")
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];
}
}
// 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);
}
}
// MediaStore (and general)
else if ("content".equalsIgnoreCase(uri.getScheme())) {
// Return the remote address
if (isGooglePhotosUri(uri)) {
return uri.getLastPathSegment();
}
return getDataColumn(context, uri, null, null);
}
// File
else if ("file".equalsIgnoreCase(uri.getScheme())) {
return uri.getPath();
}
return null;
}
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());
}
好了,以上便是我們的解決方案了。
如果大家感覺總結的還不錯,可以給我點個心,或者關注筆者一下~ 有什么問題,也隨時歡迎大家留言和我討論。