Android中頭像選擇宛琅,圖片上傳等功能幾乎是每一個APP必備的功能刻蟹,那么關于怎么使用相機,如何進行照片選擇嘿辟,以及選擇后的圖片裁剪舆瘪,這一系列的問題都需要逐一解決。這也是本篇文章的主要內(nèi)容红伦。
一英古、應用場景
微信朋友圈上傳圖片,頭像上傳等功能昙读,經(jīng)常就會用到以上功能召调。
二、業(yè)務邏輯
主要分為兩種業(yè)務邏輯:拍照蛮浑,選擇圖片唠叛。
拍照邏輯:
1.A 界面,點擊按鈕調用相機拍照沮稚;
2.拍照界面拍照后艺沼,點擊確認得到拍完照片,跳轉到 B 界面進行預覽蕴掏;
3.B 界面進行圖片裁剪障般,裁剪后確認,返回A界面進行圖片回顯盛杰;
選擇圖片邏輯:
1.A界面挽荡,點擊按鈕調用相冊選擇圖片;
2.相冊界面選擇圖片后饶唤,跳轉到B界面進行預覽徐伐;
3.B 界面進行圖片裁剪,裁剪后確認募狂,返回A界面進行圖片回顯办素;
從上面可以清楚地看出,兩種方式的主要區(qū)別在第一步上面祸穷,一種是選擇調用相機性穿,另一種選擇是調用相冊。
下面我們來介紹具體代碼邏輯雷滚。
三需曾、拍照具體實現(xiàn)
以如下使用場景為例:
<img src="http://upload-images.jianshu.io/upload_images/3985563-b82a260a49b89082.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" width = "250" height = "450" align=center />
頭像上傳的使用。
1.調用相機
Android 程序上實現(xiàn)拍照功能的方式分為兩種:第一種是利用相機的 API 來自定義相機,第二種是利用 Intent 調用系統(tǒng)指定的相機拍照呆万。下面講的內(nèi)容都是針對第二種實現(xiàn)方式的應用商源。
簡單使用
Intent captureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
Uri fileUri = Uri.fromFile(mPhotoFile);
captureIntent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);
startActivityForResult(captureIntent, CAPTURE_PHOTO_REQUEST_CODE);
很簡單,通過上述四行代碼就實現(xiàn)了調用系統(tǒng)相機谋减。
加入MediaStore.EXTRA_OUTPUT牡彻,使得拍照后的圖片輸出到對應路徑下。
然而由于Android手機的碎片化出爹,我們之前調用系統(tǒng)指定的相機app來拍照庄吼,有些手機可能會沒有這個app,所以在使用之前要檢查是否有系統(tǒng)相機严就。
/**
* 判斷系統(tǒng)中是否存在可以啟動的相機應用
*
* @return 存在返回true总寻,不存在返回false
*/
public boolean hasCamera() {
PackageManager packageManager = mActivity.getPackageManager();
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
List<ResolveInfo> list = packageManager.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
return list.size() > 0;
}
2.照片預覽及圖片裁剪
由于之前使用startActivityForResult方式調用系統(tǒng)相機,那么在拍照完成后梢为,會返回到上述頁面渐行,這時候需要重寫onActivityResult方法,根據(jù)之前傳入的mPhotoFile路徑抖誉,就獲取了圖片所在地殊轴,因為拍照后的圖片就存在該路徑下。
然后我們只需要在開啟一個照片預覽Activity袒炉,進行后續(xù)裁剪就可以了。
因為這里我們調用系統(tǒng)裁剪樊零,所以就不設置預覽Activity我磁,直接跳轉到裁剪頁面就可以了。
//拍照完成后 獲取目標文件 跳轉到裁剪頁面
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == CapturePhotoHelper.CAPTURE_PHOTO_REQUEST_CODE) {
//獲取拍照后圖片路徑
File photoFile = mCapturePhotoHelper.getPhoto();
if (photoFile != null) {
if (resultCode == RESULT_OK) {
Uri uri = Uri.fromFile(photoFile);
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("scale", true);
intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
intent.putExtra("return-data", false);
intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
intent.putExtra("noFaceDetection", true); // no face detection
intent = Intent.createChooser(intent, "裁剪圖片");
startActivityForResult(intent, REQUEST_PICKER_AND_CROP);
} else {
if (photoFile.exists()) {
photoFile.delete();
}
}
}
} else {
super.onActivityResult(requestCode, resultCode, data);
}
}
其中要注意幾個 extra 字段:
注意:return-data: 設為 true 的時候驻襟,在 onActivityResult() 中可以直接通過 data.getParcelableExtra("data") 得到裁剪后的 Bitmap 對象夺艰。但是當 Bitmap 過大時,就不能使用這種方法了沉衣,容易出現(xiàn)OOM現(xiàn)象郁副,需要通過獲取文件,然后先縮放豌习,再加載存谎。
如下圖所示:
3.回顯圖片
如上如所示,修剪圖片完成后肥隆,點擊確定既荚,然后就可以編寫回顯邏輯。
同樣在onActivityReuslt方法中
if(requestCode ==REQUEST_PICKER_AND_CROP){
File photoFile = mCapturePhotoHelper.getPhoto();
//存放到相冊
BitmapUtils.displayToGallery(this, photoFile);
//更新UI 顯示圖像
InformationBean informationBean = mList.get(0);
informationBean.setContent(photoFile.getAbsoluteFile().toString());
informationBean.setSet(true);
mAdapter.notifyItemChanged(0);
}
上述采用了RecyclerView,具體更新頭像邏輯在Adapter中栋艳。
不過同樣由于Android碎片化問題恰聘,圖片會產(chǎn)生各種各樣的問題,比如:拍出來的照片“歪了”,拍完照怎么閃退了晴叨,圖片無法顯示凿宾。
以上這些問題都比較坑,不過不要緊兼蕊,已經(jīng)有前人為我們趟出一條血路初厚,全部都處理好了,詳細代碼及具體實現(xiàn)參考:你需要知道的Android拍照適配方案遍略。
這里我們只負責應用就好了:
String content = bean.getContent();
final File file = new File(content);
((SpecialViewHolder) holder).mImageView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
((SpecialViewHolder) holder).mImageView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
mWidth = ((SpecialViewHolder) holder).mImageView.getMeasuredWidth();
mHeight = ((SpecialViewHolder) holder).mImageView.getMeasuredHeight();
Bitmap bitmap = BitmapUtils.decodeBitmapFromFile(file, mWidth, mHeight);
if (bitmap != null) {
//檢查是否有被旋轉惧所,并進行糾正
System.out.println("文件所占空間:"+"file.getTotalSpace()");
int degree = BitmapUtils.getBitmapDegree(file.getAbsolutePath());
if (degree != 0) {
bitmap = BitmapUtils.rotateBitmapByDegree(bitmap, degree);
}
((SpecialViewHolder) holder).mImageView.setImageBitmap(bitmap);
}
}
});
先獲取控件的寬高,進行壓縮绪杏,避免圖片無法顯示的問題下愈。
然后檢查有沒有被旋轉,如果旋轉蕾久,那么通過矩陣矯正势似,避免照片"歪了"的問題。
至于拍完照片后閃退僧著,可以通過重寫onSaveInstanceState 和 onRestoreInstanceState 來實現(xiàn)履因。
回顯結果:
四、選擇圖片具體實現(xiàn)
由于和上述方式只是第一步有區(qū)別盹愚,我們就具體看看第一步的實現(xiàn)栅迄。
Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
intent.putExtra(MediaStore.EXTRA_OUTPUT,uri);
startActivityForResult(intent, REQUEST_PICK_IMAGE);
直接開啟系統(tǒng)圖片選擇應用即可,不用額外設置MediaStore.EXTRA_OUTPUT皆怕,因為圖片已經(jīng)保存在數(shù)據(jù)庫內(nèi)了毅舆,可直接獲取,如下所示愈腾。
然后在onActivityResult中憋活,獲取圖片存儲路徑,跳轉到裁剪頁面虱黄。
if (requestCode == REQUEST_PICK_IMAGE) {
//獲取選擇圖片后圖片路徑
if (resultCode == RESULT_OK) {
Uri uri = data.getData();
Intent intent = new Intent("com.android.camera.action.CROP");
intent.setDataAndType(uri, "image/*");
intent.putExtra("aspectX", 1);
intent.putExtra("aspectY", 1);
intent.putExtra("outputX", 200);
intent.putExtra("outputY", 200);
intent.putExtra("scale", true);
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(tempFile));
intent.putExtra("return-data", false);
intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
intent.putExtra("noFaceDetection", true); // no face detection
intent = Intent.createChooser(intent, "裁剪圖片");
startActivityForResult(intent, REQUEST_PICKER_AND_CROP_2);
}
}
后面回顯步驟和上述一致悦即。
五、總結
上述介紹了拍照橱乱,照片選擇以及圖片剪裁的使用辜梳,由于使用的是系統(tǒng)自帶的應用,所以可能出現(xiàn)一些意想不到的適配問題仅醇,還有待解決冗美。另外,由于是系統(tǒng)自帶析二,功能比較單一粉洼,且無法使用個性化节预,如有這方面的需求,可以使用一些流行的第三方庫属韧,Github上有很多優(yōu)秀的實現(xiàn)安拟。