android 拍照本本地選擇圖片上傳
好久沒有坐下來安安靜靜的寫部落格了 ,上一篇寫的是自定義相機 ,以前專案中用過一些第三方的庫 ,萬物歸終今天找個時間總結一下 ,做開發幾年了 。隨著android studio的運用,開源資源越來越多,越來越好用 ,但是使用第三方的開原始碼,越來越不爽 ,很多庫漸漸的丟下了 ,比如說EventBus ,剛開始的時候覺得好像神奇 ,用多了 。感覺程式碼不是很直觀 ,就慢慢不用了 ,還是覺得自己寫的回撥介面好用。
好了,不說廢話了 ,一直以來開發平臺都是RK晶片 5.0系統的,有時候也做一些APK ,上次出現的androdi7.0的問題,今天整理下 。拍照,選中本地圖片,切割,老生常談,無論使用開源,還是自定義 ,現在發現還是android系統提供的好用,畢竟androi d都8.0了,越來越好用 。
android7.0 ,拍照,選擇圖片,不能和以前一樣使用了 ,增加了許可權的管理 ,直接看程式碼 。 相對以前的使用區別還是挺明顯的
0:先貼一個常量類,一會後邊要使用
public class AppConstant { /*** * 拍照返回圖片的 */ public static final String cameralSavePath = ApInfo.IMAGE_URL + "/camera.jpg"; public static final String CACHE_IMAGE = ApInfo.IMAGE_URL + "/cache.jpg";public static final String authorities = "com.mirrormobile.fileprovider"; public static final int CAMERA_IMAGE_BACK = 5612; public static final int CUT_IMAGE_BACK = 23456; public static final int IMAGE_CUT_BACK = 5617; /*** * 選擇本地相簿 */ public static final int LOCAL_FILE_BACK= 56452; public static final String TAG_LOCALFILE_BACK = "TAG_LOCALFILE_BACK";}
1:res中新建 xml 資料夾,在xml中新建file_paths.xml
patH後邊的路徑是包名
<?xml version="1.0" encoding="utf-8"?> <paths> <external-path name="files_root" path="Android/data/com.mirrormobile/" /> <external-path name="external_storage_root" path="." /> </paths>
2:在清單檔案中註冊 :com.mirrormobile 是包名
resource中是剛才新建的xml的路徑
<provider android:name="android.support.v4.content.FileProvider" android:authorities="com.mirrormobile.fileprovider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> </provider>
3:新建工具類 : ImageCutUtil,用來拍照,本地選擇,切割圖片
android 6.0 以後使用隱私的許可權,需要申請許可權,這裡我用的是HiPermission ,大家可以去github去看,使用還是挺方便的,這裡就只貼程式碼了 ,Buid.gradle中引用一下
//hipermission compile 'me.weyye.hipermission:library:1.0.7'
去請求相機許可權 ,通過後去呼叫系統
/*** * 檢查相機許可權 */ public void checkCameraPermission() { List<PermissionItem> permissions = new ArrayList<PermissionItem>(); permissions.add( new PermissionItem(Manifest.permission.CAMERA, "SD卡讀取許可權", R.drawable.permission_ic_phone)); HiPermission.create(context).title(context.getString(R.string.permission_cus_title)).permissions( permissions).msg(context.getString(R.string.permission_cus_msg)).animStyle(R.style.PermissionAnimModal).style( R.style.PermissionDefaultBlueStyle).checkMutiPermission(new PermissionCallback() { @Override public void onClose() { Log.e("main", "====onClose===="); } @Override public void onFinish() { try { takeCameraPhoto(); } catch (Exception e) { MyToastView.getInstance().Toast(context, e.toString()); Log.e("main", "====開啟相機異常====" + e.toString()); } } @Override public void onDeny(String permission, int position) { Log.e("main", "====開啟相機異常===="); MyToastView.getInstance().Toast(context, "您拒絕了" + permission + "許可權,請手動開啟"); } @Override public void onGuarantee(String permission, int position) { Log.e("main", "====onGuarantee===="); } }); }
/*** * 拍照返回 */ public void takeCameraPhoto() { try { FileUtils.creatFileNotExciet(); File file = new File(AppConstant.cameralSavePath); if (file.exists()) { file.delete(); } file.createNewFile(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { //7.0執行該方法 Uri imageUri = FileProvider.getUriForFile(context, AppConstant.authorities, file); Intent intent = new Intent(); //新增這一句表示對目標應用臨時授權該Uri所代表的檔案 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);//設定Action為拍照 intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);//將拍取的照片儲存到指定URI context.startActivityForResult(intent, AppConstant.CAMERA_IMAGE_BACK); } else { //7.0以下手機系統執行這個方法 Intent getPhoto = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); Uri uri = Uri.fromFile(file); getPhoto.putExtra(MediaStore.EXTRA_OUTPUT, uri);//根據uri儲存照片 getPhoto.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1);//儲存照片的質量 context.startActivityForResult(getPhoto, AppConstant.CAMERA_IMAGE_BACK);//啟動相機拍照 } } catch (Exception e) { MyToastView.getInstance().Toast(context, e.toString()); } }拍照的時候,判斷一下當前的系統版本,7.0以前使用的url .7.0以後是使用FileProvider來訪問本地圖片
選擇本地的圖片 ,同理,需要分系統來操作
接下來就是圖片切割了 ,7.0的使用方法相比以前的要稍微複雜一點,但是系統的切割用著舒服 ,簡單的呼叫,如果覺得介面不好看,那就智慧自己去想辦法了 ,去引用第三方 ,或者自己寫 ,註釋比較清楚,不解釋了
/*** * 裁切圖片 * @param inputUrl * 裁切圖片的url * @param outputUrl * 儲存的圖片的url */ public void cutImage(String inputUrl, String outputUrl) { try { File file_out = new File(outputUrl); if (file_out.exists()) { file_out.delete(); } file_out.createNewFile(); cropPicture(inputUrl, outputUrl); } catch (Exception e) { Log.e(TAG, "====裁切圖片異常=--" + e.toString()); MyToastView.getInstance().Toast(context, e.toString()); } } /** * 呼叫系統剪裁功能 */ public void cropPicture(String inputUrl, String output) { File fileinput = new File(inputUrl); Uri imageUri; Uri outputUri; Intent intent = new Intent("com.android.camera.action.CROP"); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); imageUri = FileProvider.getUriForFile(context, AppConstant.authorities, fileinput); outputUri = Uri.fromFile(new File(output)); } else { imageUri = Uri.fromFile(fileinput); outputUri = Uri.fromFile(new File(output)); } intent.setDataAndType(imageUri, "image/*"); intent.putExtra("crop", "true"); //設定寬高比例 intent.putExtra("aspectX", 1); intent.putExtra("aspectY", 2); //設定裁剪圖片寬高 // intent.putExtra("outputX", 300); // intent.putExtra("outputY", 300); intent.putExtra("scale", true); intent.putExtra(MediaStore.EXTRA_OUTPUT, outputUri); intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString()); intent.putExtra("noFaceDetection", true); context.startActivityForResult(intent, AppConstant.IMAGE_CUT_BACK); }
介面呼叫初始化這個工具類 ,然後直接呼叫許可權的方法就可以了,我們看一下OnActivityForResult()這個方法
String updatePath = ""; @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == AppConstant.CAMERA_IMAGE_BACK) { //拍照返回的資料 imageCutUtil.cutImage(AppConstant.cameralSavePath, AppConstant.CACHE_IMAGE); } else if (requestCode == AppConstant.LOCAL_FILE_BACK) { String filePath = data.getStringExtra(AppConstant.TAG_LOCALFILE_BACK); imageCutUtil.cutImage(filePath, AppConstant.CACHE_IMAGE); } else if (requestCode == AppConstant.IMAGE_CUT_BACK) { //切割之後返回的資料 Bitmap bitmap = BitmapFactory.decodeFile(AppConstant.CACHE_IMAGE); iv_show_image.setImageBitmap(bitmap); updatePath = AppConstant.CACHE_IMAGE; } }
選擇本地也就簡單了,結合上邊的程式碼 ,處理起來比較簡單,檢查許可權,開啟本地相簿
public void checkSdImagePermiss() { List<PermissionItem> permissions = new ArrayList<PermissionItem>(); permissions.add(new PermissionItem(Manifest.permission.READ_EXTERNAL_STORAGE, "SD卡讀取許可權", R.drawable.permission_ic_phone)); permissions.add(new PermissionItem(Manifest.permission.WRITE_EXTERNAL_STORAGE, "SD卡讀取許可權", R.drawable.permission_ic_phone)); HiPermission.create(context).title(context.getString(R.string.permission_cus_title)).permissions( permissions).msg(context.getString(R.string.permission_cus_msg)).animStyle(R.style.PermissionAnimModal).style( R.style.PermissionDefaultBlueStyle).checkMutiPermission(new PermissionCallback() { @Override public void onClose() { Log.i(TAG, "使用者拒絕我們的許可權"); } @Override public void onFinish() { try { Intent intent = new Intent(Intent.ACTION_GET_CONTENT); intent.addCategory(Intent.CATEGORY_OPENABLE); intent.setType("image/*"); context.startActivityForResult(intent, AppConstant.LOCAL_FILE_BACK); // Intent intent = new Intent(context, LoImgChooiceActivity.class); // context.startActivityForResult(intent, AppConstant.LOCAL_FILE_BACK); } catch (Exception e) { Log.e("main", "====開啟相機異常====" + e.toString()); } }
介面的onActivityForResult(),接受到資料,直接吧資料丟給Util去處理
String updatePath = ""; @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == AppConstant.CAMERA_IMAGE_BACK) { //拍照返回的資料 imageCutUtil.cutImage(AppConstant.cameralSavePath, AppConstant.CACHE_IMAGE); } else if (requestCode == AppConstant.LOCAL_FILE_BACK) { //本地圖片選擇 imageCutUtil.cutImageLocal(data); // String filePath = data.getStringExtra(AppConstant.TAG_LOCALFILE_BACK); // imageCutUtil.cutImage(filePath, AppConstant.CACHE_IMAGE); } else if (requestCode == AppConstant.IMAGE_CUT_BACK) { //切割之後返回的資料 Bitmap bitmap = BitmapFactory.decodeFile(AppConstant.CACHE_IMAGE); iv_show_image.setImageBitmap(bitmap); updatePath = AppConstant.CACHE_IMAGE; } }
/*** * 本地圖片選擇器 * @param data */ public void cutImageLocal(Intent data) { Uri imageUri = data.getData(); String url_out = AppConstant.CACHE_IMAGE; File file_out = new File(AppConstant.CACHE_IMAGE); if (file_out.exists()) { file_out.delete(); } Uri outputUri = Uri.fromFile(new File(url_out)); cutImage(imageUri, outputUri); }直接獲取圖片的URI ,然後直接去裁切 。下面貼上全部程式碼 ;
package com.mirror.mobile.util.image; import android.Manifest; import android.app.Activity; import android.content.Intent; import android.database.Cursor; import android.graphics.Bitmap; import android.net.Uri; import android.os.Build; import android.provider.MediaStore; import android.support.v4.content.FileProvider; import android.util.Log; import com.cdl.dialog.toast.MyToastView; import com.mirror.mobile.test.LoImgChooiceActivity; import com.mirror.mobile.util.FileUtils; import com.mirror.mobile.util.updatepic.AppConstant; import com.mirrormobile.R; import java.io.File; import java.util.ArrayList; import java.util.List; import me.weyye.hipermission.HiPermission; import me.weyye.hipermission.PermissionCallback; import me.weyye.hipermission.PermissionItem; /*** * 圖片裁剪工具類 */ public class ImageCutUtil { Activity context; private static final String TAG = "MAIN"; public ImageCutUtil(Activity context) { this.context = context; } //=============================================================================================================================== /*** * 本地圖片選擇器 * @param data */ public void cutImageLocal(Intent data) { Uri imageUri = data.getData(); String url_out = AppConstant.CACHE_IMAGE; File file_out = new File(AppConstant.CACHE_IMAGE); if (file_out.exists()) { file_out.delete(); } Uri outputUri = Uri.fromFile(new File(url_out)); cutImage(imageUri, outputUri); } //============================================================================================================================================ public void cutImage(String inputUrl, String output) { try { File file_out = new File(output); if (file_out.exists()) { file_out.delete(); } file_out.createNewFile(); File fileinput = new File(inputUrl); Uri imageUri; Uri outputUri; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { imageUri = FileProvider.getUriForFile(context, AppConstant.authorities, fileinput); outputUri = Uri.fromFile(new File(output)); } else { imageUri = Uri.fromFile(fileinput); outputUri = Uri.fromFile(new File(output)); } cutImage(imageUri, outputUri); } catch (Exception e) { } } public void cutImage(Uri imageUri, Uri outputUri) { try { Intent intent = new Intent("com.android.camera.action.CROP"); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); } intent.setDataAndType(imageUri, "image/*"); intent.putExtra("crop", "true"); //設定寬高比例 intent.putExtra("aspectX", 1); intent.putExtra("aspectY", 2); intent.putExtra("scale", true); intent.putExtra(MediaStore.EXTRA_OUTPUT, outputUri); intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString()); intent.putExtra("noFaceDetection", true); context.startActivityForResult(intent, AppConstant.IMAGE_CUT_BACK); } catch (Exception e) { } } // public void cutImage(String inputUrl, String output) { // try { // File file_out = new File(output); // if (file_out.exists()) { // file_out.delete(); // } // file_out.createNewFile(); // File fileinput = new File(inputUrl); // Uri imageUri; // Uri outputUri; // Intent intent = new Intent("com.android.camera.action.CROP"); // if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { // intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); // imageUri = FileProvider.getUriForFile(context, AppConstant.authorities, fileinput); // outputUri = Uri.fromFile(new File(output)); // } else { // imageUri = Uri.fromFile(fileinput); // outputUri = Uri.fromFile(new File(output)); // } // intent.setDataAndType(imageUri, "image/*"); // intent.putExtra("crop", "true"); // //設定寬高比例 // intent.putExtra("aspectX", 1); // intent.putExtra("aspectY", 2); // //設定裁剪圖片寬高 // // intent.putExtra("outputX", 300); // // intent.putExtra("outputY", 300); // intent.putExtra("scale", true); // intent.putExtra(MediaStore.EXTRA_OUTPUT, outputUri); // intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString()); // intent.putExtra("noFaceDetection", true); // context.startActivityForResult(intent, AppConstant.IMAGE_CUT_BACK); // } catch (Exception e) { // } // } public void checkSdImagePermiss() { List<PermissionItem> permissions = new ArrayList<PermissionItem>(); permissions.add(new PermissionItem(Manifest.permission.READ_EXTERNAL_STORAGE, "SD卡讀取許可權", R.drawable.permission_ic_phone)); permissions.add(new PermissionItem(Manifest.permission.WRITE_EXTERNAL_STORAGE, "SD卡讀取許可權", R.drawable.permission_ic_phone)); HiPermission.create(context).title(context.getString(R.string.permission_cus_title)).permissions( permissions).msg(context.getString(R.string.permission_cus_msg)).animStyle(R.style.PermissionAnimModal).style( R.style.PermissionDefaultBlueStyle).checkMutiPermission(new PermissionCallback() { @Override public void onClose() { Log.i(TAG, "使用者拒絕我們的許可權"); } @Override public void onFinish() { try { Intent intent = new Intent(Intent.ACTION_GET_CONTENT); intent.addCategory(Intent.CATEGORY_OPENABLE); intent.setType("image/*"); context.startActivityForResult(intent, AppConstant.LOCAL_FILE_BACK); // Intent intent = new Intent(context, LoImgChooiceActivity.class); // context.startActivityForResult(intent, AppConstant.LOCAL_FILE_BACK); } catch (Exception e) { Log.e("main", "====開啟相機異常====" + e.toString()); } } @Override public void onDeny(String permission, int position) { MyToastView.getInstance().Toast(context, "您拒絕了" + permission + "許可權,請手動開啟"); Log.i(TAG, "使用者禁止了許可權" + permission); } @Override public void onGuarantee(String permission, int position) { Log.i(TAG, "onGuarantee"); } }); } /*** * 檢查相機許可權 */ public void checkCameraPermission() { List<PermissionItem> permissions = new ArrayList<PermissionItem>(); permissions.add( new PermissionItem(Manifest.permission.CAMERA, "SD卡讀取許可權", R.drawable.permission_ic_phone)); HiPermission.create(context).title(context.getString(R.string.permission_cus_title)).permissions( permissions).msg(context.getString(R.string.permission_cus_msg)).animStyle(R.style.PermissionAnimModal).style( R.style.PermissionDefaultBlueStyle).checkMutiPermission(new PermissionCallback() { @Override public void onClose() { Log.e("main", "====onClose===="); } @Override public void onFinish() { try { takeCameraPhoto(); } catch (Exception e) { MyToastView.getInstance().Toast(context, e.toString()); Log.e("main", "====開啟相機異常====" + e.toString()); } } @Override public void onDeny(String permission, int position) { Log.e("main", "====開啟相機異常===="); MyToastView.getInstance().Toast(context, "您拒絕了" + permission + "許可權,請手動開啟"); } @Override public void onGuarantee(String permission, int position) { Log.e("main", "====onGuarantee===="); } }); } /*** * 拍照返回 */ public void takeCameraPhoto() { try { FileUtils.creatFileNotExciet(); File file = new File(AppConstant.cameralSavePath); if (file.exists()) { file.delete(); } file.createNewFile(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { //7.0執行該方法 Uri imageUri = FileProvider.getUriForFile(context, AppConstant.authorities, file); Intent intent = new Intent(); //新增這一句表示對目標應用臨時授權該Uri所代表的檔案 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);//設定Action為拍照 intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);//將拍取的照片儲存到指定URI context.startActivityForResult(intent, AppConstant.CAMERA_IMAGE_BACK); } else { //7.0以下手機系統執行這個方法 Intent getPhoto = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); Uri uri = Uri.fromFile(file); getPhoto.putExtra(MediaStore.EXTRA_OUTPUT, uri);//根據uri儲存照片 getPhoto.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1);//儲存照片的質量 context.startActivityForResult(getPhoto, AppConstant.CAMERA_IMAGE_BACK);//啟動相機拍照 } } catch (Exception e) { MyToastView.getInstance().Toast(context, e.toString()); } } }
介面拍照 ,獲取相簿程式碼
@Override public void clickFirst() { //拍照 imageCutUtil.checkCameraPermission(); } @Override public void clickSecond() { //本地取圖片 imageCutUtil.checkSdImagePermiss(); }
String updatePath = ""; @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == AppConstant.CAMERA_IMAGE_BACK) { //拍照返回的資料 imageCutUtil.cutImage(AppConstant.cameralSavePath, AppConstant.CACHE_IMAGE); } else if (requestCode == AppConstant.LOCAL_FILE_BACK) { //本地圖片選擇 imageCutUtil.cutImageLocal(data); // String filePath = data.getStringExtra(AppConstant.TAG_LOCALFILE_BACK); // imageCutUtil.cutImage(filePath, AppConstant.CACHE_IMAGE); } else if (requestCode == AppConstant.IMAGE_CUT_BACK) { //切割之後返回的資料 Bitmap bitmap = BitmapFactory.decodeFile(AppConstant.CACHE_IMAGE); iv_show_image.setImageBitmap(bitmap); updatePath = AppConstant.CACHE_IMAGE; } }