趁着國慶有時間咱們來聊一聊最經常使用的選取用戶圖片一系列的功能,go!html
效果展現
效果展現連接android
咱們以前設置拍照保存的文件地址的Uri,都是直接Intent.putExtra(MediaStore.EXTRA_OUTPUT,文件保存的Uri路徑),可是7.0以後,對用戶權限提升了保護,以前那種方式行不通了,因此咱們要作7.0的判斷,用FileProvider獲取設置保存的文件Uri,而後放到Intent.putExtra(MediaStore.EXTRA_OUTPUT,文件保存的Uri路徑)中,代碼以下:git
//相機拍照的一個標識,後面用 TAKEPAHTO = 1; // 啓動系統相機 Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); //7.0如下設置保存圖片的地址 Uri norTakePhotoSaveAdr; // 判斷7.0android系統 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { //臨時添加一個拍照權限 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); // //經過FileProvider獲取保存圖片file的uri(先建立file,而後獲取File的Uri) takePhotoSaveAdr = FileProvider.getUriForFile(MainActivity.this, "com.hxzk.bj.photodemo", new File(Environment.getExternalStorageDirectory(), "savephoto.jpg")); //MediaStore.EXTRA_OUTPUT-此設置須要一個保存視頻的路徑和文件名的Uri intent.putExtra(MediaStore.EXTRA_OUTPUT, takePhotoSaveAdr); } else { norTakePhotoSaveAdr = Uri.fromFile(new File(Environment.getExternalStorageDirectory(), "savephoto.jpg")); intent.putExtra(MediaStore.EXTRA_OUTPUT, norTakePhotoSaveAdr); } //PHOTO_TAKEPHOTO,相機的一個請求碼,返回時要用 startActivityForResult(intent, PHOTO_TAKEPHOTO);
相比較拍照,相冊要簡單一點,代碼中都有註釋,直接看:github
//拍照的一個表示 TAKEPAHTO = 0; //調用系統圖庫,選擇圖片 //Intent.ACTION_PICK 意思是選擇數據,其具體表達有: // Intent intent = new Intent(Intent.ACTION_GET_CONTENT); //intent.setType("image/*"); 獲取本地圖片 // intent.setType("video/*"); 獲取本地視頻 //intent.setType("audio/*") 獲取本地音樂 // Intent intent = new Intent(Intent.ACTION_PICK); // intent.setType(ContactsContract.Contacts.CONTENT_TYPE); //獲取聯繫人 // startActivityForResult(intent, PICK_CONTACT); //第二種寫法 Intent intent = new Intent(Intent.ACTION_PICK, null); //其中External爲sdcard下的多媒體文件,Internal爲system下的多媒體文件。 //使用INTERNAL_CONTENT_URI只能顯示存儲在內部的照片 intent.setDataAndType( MediaStore.Images.Media.INTERNAL_CONTENT_URI, "image/*"); //返回結果和標識 startActivityForResult(intent, PHOTO_PHOTOALBUM);
不管是拍照仍是選取圖片,咱們都要在Activity的onActivityResult中去獲取返回結果,而後進行下一步操做。這裏提一下,咱們在跳轉相冊或拍照都有一個requestCode,如圖:
startActivityForResult(intent, PHOTO_PHOTOALBUM);
這個,咱們全局定義了三個,分別是拍照,相冊,裁剪的標識:安全
//三個常量全局標識 //圖庫 private static final int PHOTO_PHOTOALBUM = 0; //拍照 private static final int PHOTO_TAKEPHOTO = 1; //裁剪 private static final int PHOTO_PHOTOCLIP = 2;
在onActivityResult中就要用來區分了:網絡
沒啥說的!ide
圖片的裁剪咱們主要看一下starPhotoZoom()這個裁剪方法,代碼以下:優化
public void startPhotoZoom(Uri uri) { Log.e("uri=====", "" + uri); //com.android.camera.action.CROP,這個action是調用系統自帶的圖片裁切功能 Intent intent = new Intent("com.android.camera.action.CROP"); intent.setDataAndType(uri, "image/*");//裁剪的圖片uri和圖片類型 intent.putExtra("crop", "true");//設置容許裁剪,若是不設置,就會跳過裁剪的過程,還能夠設置putExtra("crop", "circle") intent.putExtra("aspectX", 1);//裁剪框的 X 方向的比例,須要爲整數 intent.putExtra("aspectY", 1);//裁剪框的 Y 方向的比例,須要爲整數 intent.putExtra("outputX", 60);//返回數據的時候的X像素大小。 intent.putExtra("outputY", 60);//返回數據的時候的Y像素大小。 //uritempFile爲Uri類變量,實例化uritempFile if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { if (TAKEPAHTO == 1) {//若是是7.0的拍照 //開啓臨時訪問的讀和寫權限 intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION); //針對7.0以上的操做 intent.setClipData(ClipData.newRawUri(MediaStore.EXTRA_OUTPUT, uri)); uriClipUri = uri; } else {//若是是7.0的相冊 //設置裁剪的圖片地址Uri uriClipUri = Uri.parse("file://" + "/" + Environment.getExternalStorageDirectory().getPath() + "/" + "clip.jpg"); } } else { uriClipUri = Uri.parse("file://" + "/" + Environment.getExternalStorageDirectory().getPath() + "/" + "clip.jpg"); } Log.e("uriClipUri=====", "" + uriClipUri); //Android 對Intent中所包含數據的大小是有限制的,通常不能超過 1M,不然會使用縮略圖 ,因此咱們要指定輸出裁剪的圖片路徑 intent.putExtra(MediaStore.EXTRA_OUTPUT, uriClipUri); intent.putExtra("return-data", false);//是否將數據保留在Bitmap中返回 intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());//輸出格式,通常設爲Bitmap格式及圖片類型 intent.putExtra("noFaceDetection", true);//人臉識別功能 startActivityForResult(intent, PHOTO_PHOTOCLIP);//裁剪完成的標識 }
我直接上方法吧:ui
/** * 圖片壓縮的方法(只是內存減小,避免oom,圖片自己在disk盤體積不變) * 顯示的Bitmap佔用的內存少一點,仍是須要去設置加載的像素長度和寬度(變成縮略圖) */ public void compressPhto(File mFile){ // BitmapFactory這個類就提供了多個解析方法(decodeResource、decodeStream、decodeFile等)用於建立Bitmap。 // 好比若是圖片來源於網絡,就可使用decodeStream方法; // 若是是sd卡里面的圖片,就能夠選擇decodeFile方法; // 若是是資源文件裏面的圖片,就可使用decodeResource方法等 BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; // 獲取當前圖片的邊界大小 //BitmapFactory.decodeResource(getResources(), R.drawable.bg, options); BitmapFactory.decodeFile(mFile.getAbsolutePath(),options); int outHeight = options.outHeight; //獲取圖片自己的高像素 int outWidth = options.outWidth;//獲取圖片自己的寬的像素 String outMimeType = options.outMimeType; options.inJustDecodeBounds = false; //inSampleSize的做用就是能夠把圖片的長短縮小inSampleSize倍,所佔內存縮小inSampleSize的平方 //對於inSampleSize值的大小有要求,最好是整數且2的倍數 options.inSampleSize = caculateSampleSize(options, 500, 500); //etPath()獲得的是構造file的時候的路徑。getAbsolutePath()獲得的是全路徑 String path =mFile.getPath(); String absPath=mFile.getAbsolutePath(); Bitmap bitmap = BitmapFactory.decodeFile(absPath,options); ivUserPhoto.setImageBitmap(bitmap); //尺寸壓縮結果 ivSize.setImageBitmap(bitmap); } /** * 計算出所須要壓縮的大小 * @param options * @param reqWidth 但願的圖片寬大小 * @param reqHeight 但願的圖片高大小 * @return */ private int caculateSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) { int sampleSize = 1; int picWidth = options.outWidth; int picHeight = options.outHeight; if (picWidth > reqWidth || picHeight > reqHeight) { int halfPicWidth = picWidth / 2; int halfPicHeight = picHeight / 2; while (halfPicWidth / sampleSize > reqWidth || halfPicHeight / sampleSize > reqHeight) { sampleSize *= 2; } } return sampleSize; }
不知道,你們注意裁剪方法裏的這一段代碼沒?this
還有拍照的這一段代碼:
爲何要這麼寫呢?
原來7.0一下版本咱們,直接調用相機獲取的圖片地址是:
file:///storage/emulated/0/temp.jpg的文件
然而7.0以後就變成:
content://........文件,使用 content://代替了 file:///
這是由於:Android 爲了提升私有文件的安全性,從 7.0 開始對外傳遞file://類型的uri會觸發FileUriExposedException。所以,在分享私有文件時必須使用FileProvider。
那麼若是在使用以前的方法就會報錯,咱們要給程序在manifest文件中加入FileProvider:
咱們看看provider_paths這個文件中都有啥?
這注解寫的,不會,就轉行吧。
直接加載圖片顯示
上傳圖片
但還有中狀況是咱們要上傳加載的圖片,我也給你們提供了方法:
Bitmap photoBitmap; File file; /** * 上傳圖片 */ public void upDateFile() { try { //裁剪後的圖像轉成BitMap photoBitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(uriClipUri)); } catch (FileNotFoundException e) { e.printStackTrace(); } //建立路徑 String path = Environment.getExternalStorageDirectory() .getPath() + "/Pic"; //獲取外部儲存目錄 file = new File(path); //建立新目錄, 建立此抽象路徑名指定的目錄,包括建立必需但不存在的父目錄。 file.mkdirs(); //以當前時間從新命名文件 long time = System.currentTimeMillis(); //生成新的文件 file = new File(file.toString() + "/" + time+ ".png"); //建立輸出流 OutputStream out = null; try { out = new FileOutputStream(file.getPath()); } catch (FileNotFoundException e) { e.printStackTrace(); } //壓縮文件,返回結果,true說明成功了 boolean bCompress = photoBitmap.compress(Bitmap.CompressFormat.JPEG, 100, out); }
暫時這麼多,之後補充!
Github地址
做者:薛之濤 連接:https://www.jianshu.com/p/832d723039da 來源:簡書 簡書著做權歸做者全部,任何形式的轉載都請聯繫做者得到受權並註明出處。