Android7.0拍照以及使用uCrop裁剪

張欽發表於2017-09-14

一、引入

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

二、拍照及相簿

  1. FileProvider

    想必FileProvider大家都很熟悉了,但是想了一下感覺還是寫一下比較好。

    1. 在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>複製程式碼
    2. 在 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>複製程式碼
  2. 呼叫相機拍照

     // 全域性變數
     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("攝像頭未準備好!");
         }
     }複製程式碼
  3. 相簿選圖

     // 全域性變數
     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);
     }複製程式碼
  4. 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;複製程式碼

三、圖片剪裁(重點)

  1. 因為用原生的一直是各種報錯,所以我這裡用的是UCrop,大家可能都見過官方的展示圖,介面可能在有些需求下顯得過於複雜,但是真正使用起來感覺有很多都是可以修改的哈哈哈!推薦大家看一下官方的例子。專案地址:github.com/Yalantis/uC…

  2. 簡單說一下引入方法但是並不能保證是最新的

    1. 依賴

       compile 'com.github.yalantis:ucrop:2.2.1'複製程式碼
    2. 在AndroidManifest中新增Activity

       <activity
           android:name="com.yalantis.ucrop.UCropActivity"
           android:screenOrientation="portrait"
           android:theme="@style/Theme.AppCompat.Light.NoActionBar"/>複製程式碼
  3. 剪下圖片

     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);
     }複製程式碼
  4. 剪下完圖片的回掉

     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;
         }
     }複製程式碼
  5. 完整的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…

相關文章