前言
在我們的日常開發(fā)當(dāng)中,調(diào)用相機(jī)和從相冊中選擇照片裁剪并上傳是很常見的功能,網(wǎng)上有很多框架,但是導(dǎo)入別人的庫, 無疑增加了App的體積,因此這里講一下如何使用系統(tǒng)自帶的相機(jī),相冊,并裁剪,個人感覺還行
第一步 : FileProvider準(zhǔn)備相關(guān)
- 在AndroidManifest.xml中增加provider節(jié)點(diǎn)蹲姐,如下:
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.dream.takephotodemo"
android:grantUriPermissions="true"
android:exported="false">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/filepaths" />
</provider>
其中: android:authorities 表示授權(quán)列表,填寫你的應(yīng)用包名忙厌,當(dāng)有多個授權(quán)時江咳,用分號隔開 android:exported 表示該內(nèi)容提供器(ContentProvider)是否能被第三方程序組件使用,必須為false爹土,否則會報異常:ava.lang.RuntimeException: Unable to get provider android.support.v4.content.FileProvider: java.lang.SecurityException: Provider must not be exported android:grantUriPermissions="true" 表示授予 URI 臨時訪問權(quán)限 android:resource 屬性指向我們自及創(chuàng)建的xml文件的路徑,文件名隨便起
-
接下來社露,我們需要在資源(res)目錄下創(chuàng)建一個xml目錄琼娘,并建立一個以上面名字為文件名的xml文件,內(nèi)容如下:
<?xml version="1.0" encoding="utf-8"?> <paths> <external-path path="." name="external_path" /> </paths>
其中: external-path 代表根目錄為: Environment.getExternalStorageDirectory() 瞒瘸,也可以寫其他的熄浓,如: files-path 代表根目錄為:Context.getFilesDir() cache-path 代表根目錄為:getCacheDir() 其path屬性的值代表路徑后層級名稱,為空則代表就是根目錄俯在,假如為“pictures”,就代表對應(yīng)根目錄下的pictures目錄
第二步:使用FileProvider
-
在這之前惯雳,我們需要在AndroidManifest.xml中增加必要的讀寫權(quán)限:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
1. 通過相機(jī)獲取圖片
/**
* 拍照
*/
private void takePhoto() {
//用于保存調(diào)用相機(jī)拍照后所生成的文件
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
return;
}
captureFile = new File(rootFile, "temp.jpg");
//跳轉(zhuǎn)到調(diào)用系統(tǒng)相機(jī)
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
//判斷版本 如果在Android7.0以上,使用FileProvider獲取Uri
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
intent.setFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
Uri contentUri = FileProvider.getUriForFile(mContext, getPackageName(), captureFile);
intent.putExtra(MediaStore.EXTRA_OUTPUT, contentUri);
} else {
//否則使用Uri.fromFile(file)方法獲取Uri
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(captureFile));
}
startActivityForResult(intent, REQUEST_PERMISSION_CAMERA);
}
2. 通過相冊獲取圖片
/**
* 從相冊選擇
*/
private void choosePhoto() {
Intent photoPickerIntent = new Intent(Intent.ACTION_PICK);
photoPickerIntent.setType("image/*");
startActivityForResult(photoPickerIntent, REQUEST_PERMISSION_WRITE);
}
3. 圖片裁剪
/**
* 裁剪圖片
*/
private void cropPhoto(Uri uri) {
cropFile = new File(rootFile, "avatar.jpg");
Intent intent = new Intent("com.android.camera.action.CROP");
intent.setDataAndType(uri, "image/*");
intent.putExtra("crop", "true");
intent.putExtra("aspectX", 1);
intent.putExtra("aspectY", 1);
intent.putExtra("outputX", 300);
intent.putExtra("outputY", 300);
intent.putExtra("return-data", false);//注意這里返回false,因?yàn)樵诓糠质謾C(jī)上獲取不到返回的數(shù)據(jù)
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(cropFile));
intent.putExtra("outputFormat", Bitmap.CompressFormat.PNG.toString());
intent.putExtra("noFaceDetection", true);
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivityForResult(intent, CROP_REQUEST_CODE);
}
第三步:接收圖片信息
-
我們在onActivityResult方法中獲得返回的圖片信息,在這里我們會先調(diào)用剪裁去剪裁圖片,然后對剪裁返回的圖片進(jìn)行設(shè)置、保存拙吉、上傳等操作
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (resultCode == RESULT_OK) { switch (requestCode) { case REQUEST_PERMISSION_CAMERA: if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { Uri contentUri = FileProvider.getUriForFile(mContext, getPackageName(), captureFile); cropPhoto(contentUri); } else { cropPhoto(Uri.fromFile(captureFile)); } break; case REQUEST_PERMISSION_WRITE: cropPhoto(data.getData()); break; case CROP_REQUEST_CODE: saveImage(cropFile.getAbsolutePath()); ivAvatar.setImageBitmap(BitmapFactory.decodeFile(cropFile.getAbsolutePath())); break; default: break; } } super.onActivityResult(requestCode, resultCode, data); }
-
保存圖片到本地
public String saveImage(String path) { if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { return null; } Bitmap bitmap = BitmapFactory.decodeFile(path); try { FileOutputStream fos = new FileOutputStream(cropFile); bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos); fos.flush(); fos.close(); return cropFile.getAbsolutePath(); } catch (IOException e) { e.printStackTrace(); } return null; }
至此筷黔,對Android7.0的兼容就結(jié)束了佛舱,注意在調(diào)用相機(jī)和裁剪時,傳入的Uri需要使用FileProvider來獲取
總結(jié)
拍照或從相冊中選取時,我們首先要判斷是否有拍照或讀寫SD卡的權(quán)限,如果沒有則需要動態(tài)申請權(quán)限,這里我用的一個第三方庫傳送門,有了權(quán)限之后在進(jìn)行下一步操作,還需要注意判斷當(dāng)前SD卡是否可用,做了這些判斷之后,相信調(diào)用系統(tǒng)的拍照或者從相冊中選擇將會變得很簡單
最后附上Demo地址傳送門