一、引入
- Android在7.0中修改了檔案許可權,所以從Android7.0開始要使用FileProvider來處理uri,從網上找了好多文章,解決了在7.0下拍照及相簿選圖的問題,但是參照網上的解決方案前切圖片一直搞不定,最終使用了UCrop進行剪下圖片並返回檔案地址,便於與伺服器互動。
- 本文主要介紹在Android7.0上進行拍照,相簿選圖以及相應的圖片剪下,當然也會向下相容,同時我也在Android4.3的手機上進行了測試,在文章最後我會附上原始碼,會有我自認為詳細的註釋哈哈。

二、拍照及相簿
FileProvider
想必FileProvider大家都很熟悉了,但是想了一下感覺還是寫一下比較好。
在manifest中配置
<application ... ... <provider android:name="android.support.v4.content.FileProvider" android:authorities="com.sdwfqin.sample.fileprovider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths_public"/> </provider> </application>複製程式碼
在 res 目錄下新建資料夾 xml 然後建立資原始檔 file_paths_public(名字隨意,但是要和manifest中的名字匹配)
<?xml version="1.0" encoding="utf-8"?> <paths> <!--照片--> <external-path name="my_images" path="Pictures"/> <!--下載--> <paths> <external-path name="download" path=""/> </paths> </paths>複製程式碼
呼叫相機拍照
// 全域性變數 public static final int RESULT_CODE_1 = 201; // 7.0 以上的uri private Uri mProviderUri; // 7.0 以下的uri private Uri mUri; // 圖片路徑 private String mFilepath = SDCardUtils.getSDCardPath() + "AndroidSamples"; ----------- /** * 拍照 */ private void camera() { File file = new File(mFilepath, System.currentTimeMillis() + ".jpg"); if (!file.getParentFile().exists()) { file.getParentFile().mkdirs(); } Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); // Android7.0以上URI if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { //通過FileProvider建立一個content型別的Uri mProviderUri = FileProvider.getUriForFile(this, "com.sdwfqin.sample.fileprovider", file); intent.putExtra(MediaStore.EXTRA_OUTPUT, mProviderUri); //新增這一句表示對目標應用臨時授權該Uri所代表的檔案 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); } else { mUri = Uri.fromFile(file); intent.putExtra(MediaStore.EXTRA_OUTPUT, mUri); } try { startActivityForResult(intent, RESULT_CODE_1); } catch (ActivityNotFoundException anf) { ToastUtils.showShort("攝像頭未準備好!"); } }複製程式碼
相簿選圖
// 全域性變數 public static final int RESULT_CODE_2 = 202; ---------- private void selectImg() { Intent pickIntent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI); pickIntent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*"); startActivityForResult(pickIntent, RESULT_CODE_2); }複製程式碼
onActivityResult
需要注意的是拍照沒有返回資料,用之前的uri就可以,從相簿查詢圖片會返回uri
case RESULT_CODE_1: if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { // 呼叫裁剪方法 cropRawPhoto(mProviderUri); } else { cropRawPhoto(mUri); } break; case RESULT_CODE_2: Log.i(TAG, "onActivityResult: " + data.getData()); cropRawPhoto(data.getData()); break;複製程式碼
三、圖片剪裁(重點)
因為用原生的一直是各種報錯,所以我這裡用的是UCrop,大家可能都見過官方的展示圖,介面可能在有些需求下顯得過於複雜,但是真正使用起來感覺有很多都是可以修改的哈哈哈!推薦大家看一下官方的例子。專案地址:github.com/Yalantis/uC…
簡單說一下引入方法但是並不能保證是最新的
依賴
compile 'com.github.yalantis:ucrop:2.2.1'複製程式碼
在AndroidManifest中新增Activity
<activity android:name="com.yalantis.ucrop.UCropActivity" android:screenOrientation="portrait" android:theme="@style/Theme.AppCompat.Light.NoActionBar"/>複製程式碼
剪下圖片
public void cropRawPhoto(Uri uri) { // 修改配置引數(我這裡只是列出了部分配置,並不是全部) UCrop.Options options = new UCrop.Options(); // 修改標題欄顏色 options.setToolbarColor(getResources().getColor(R.color.colorPrimary)); // 修改狀態列顏色 options.setStatusBarColor(getResources().getColor(R.color.colorPrimaryDark)); // 隱藏底部工具 options.setHideBottomControls(true); // 圖片格式 options.setCompressionFormat(Bitmap.CompressFormat.JPEG); // 設定圖片壓縮質量 options.setCompressionQuality(100); // 是否讓使用者調整範圍(預設false),如果開啟,可能會造成剪下的圖片的長寬比不是設定的 // 如果不開啟,使用者不能拖動選框,只能縮放圖片 options.setFreeStyleCropEnabled(true); // 設定源uri及目標uri UCrop.of(uri, Uri.fromFile(new File(mFilepath, System.currentTimeMillis() + ".jpg"))) // 長寬比 .withAspectRatio(1, 1) // 圖片大小 .withMaxResultSize(200, 200) // 配置引數 .withOptions(options) .start(this); }複製程式碼
剪下完圖片的回掉
if (resultCode == UCrop.RESULT_ERROR){ mCameraTv.setText(UCrop.getError(data) + ""); showMsg("圖片剪裁失敗"); return; } if (resultCode == RESULT_OK) { switch (requestCode) { case UCrop.REQUEST_CROP: // 成功(返回的是檔案地址) Log.i(TAG, "onActivityResult: " + UCrop.getOutput(data)); mCameraTv.setText(UCrop.getOutput(data) + ""); // 使用Glide顯示圖片 Glide.with(this) .load(UCrop.getOutput(data)) .crossFade() .into(mCameraImg); break; } }複製程式碼
完整的onActivityResult,包含拍照的回掉
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode == UCrop.RESULT_ERROR){ mCameraTv.setText(UCrop.getError(data) + ""); showMsg("圖片剪裁失敗"); return; } if (resultCode == RESULT_OK) { switch (requestCode) { case RESULT_CODE_1: if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { cropRawPhoto(mProviderUri); } else { cropRawPhoto(mUri); } break; case RESULT_CODE_2: Log.i(TAG, "onActivityResult: " + data.getData()); cropRawPhoto(data.getData()); break; case UCrop.REQUEST_CROP: Log.i(TAG, "onActivityResult: " + UCrop.getOutput(data)); mCameraTv.setText(UCrop.getOutput(data) + ""); Glide.with(this) .load(UCrop.getOutput(data)) .crossFade() .into(mCameraImg); break; } } }複製程式碼
```
四、原始碼
原始碼地址:github.com/sdwfqin/And…