? ? ? ? 在實際開發中,遇到頭像修改功能,我們一般是向用戶提供相冊,拍照以及裁剪功能。而在這個功能開發中,我們需要考慮Android6.0權限適配以及圖片壓縮上傳。雖然功能很普通,但是里面有很多坑要跳過。廢話少說,直接進入正題。
第一步:圖片選擇框的彈出
? ? 圖片選擇方式對話框的展示形式根據產品UI來定,但是主要展示的是相機、相冊以及取消按鈕,代碼如下:
//彈出圖片選擇框
public void choicePhoto(Fragment context, File file){
????????this.cameraFile = file; ? ? ? ?//這個是提前創建的用來存儲相機拍照的圖片
????????final Dialog dialog =new Dialog(context.getActivity(), R.style.Theme_Light_Dialog);
????????View view = LayoutInflater.from(context.getActivity()).inflate(R.layout.dialog_photo,null);
????????Window window = dialog.getWindow();
????????window.setGravity(Gravity.BOTTOM);
????????window.setWindowAnimations(R.style.dialog);
????????window.getDecorView().setPadding(13,0,13,10);
????????WindowManager.LayoutParams layoutParams = window.getAttributes();
????????layoutParams.width = WindowManager.LayoutParams.MATCH_PARENT;
????????layoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
????????layoutParams.alpha =1.0f;
????????window.setAttributes(layoutParams);
????????dialog.setContentView(view);
????????Button fromCamera = (Button) view.findViewById(R.id.fromcamera);//相機獲取
? ????? Button fromGallery = (Button) view.findViewById(R.id.fromgallery);//相冊獲取
? ? ????Button cancle = (Button) view.findViewById(R.id.cancel_getphoto);
????????//拍照獲取
? ? ????fromCamera.setOnClickListener(new View.OnClickListener() {
????????????????@Override
? ? ? ? ? ? ? ? ? public void onClick(View v) {
????????????????????????dialog.dismiss();
????????????????????????//拍照權限適配
? ? ? ? ? ? ????????????RxPermissions rxPermissions =new RxPermissions(context.getActivity());
????????????????????????rxPermissions.request(Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.CAMERA).subscribe(aBoolean ????????????????????????-> {
????????????????????????????????if (aBoolean) {
????????????????????????????????????fromCamera(context);
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?}else {
????????????????????????????????????????//未獲取權限
? ? ? ? ? ? ? ? ? ? ????????????????????Toast.makeText(context.getActivity(),"您沒有授權該權限,請在設置中打開授權", Toast.LENGTH_SHORT).show();
????????????????????????????????}
????????????????????????????});
????????????????????????}
????????????????});
????????????//手機相冊獲取
? ? ????????fromGallery.setOnClickListener(new View.OnClickListener() {
????????????????????@Override
? ? ? ????????????? public void onClick(View v) {
????????????????????????????dialog.dismiss();
????????????????????????????RxPermissions rxPermissions =new RxPermissions(context.getActivity());
????????????????????????????rxPermissions.request(Manifest.permission.WRITE_EXTERNAL_STORAGE).subscribe(aBoolean -> {
????????????????????????????????????if (aBoolean) {
????????????????????????????????????????????fromGallery(context);
????????????????????????????????????}else {
????????????????????????????????????????????//未獲取權限
? ? ? ? ? ? ? ? ? ? ????????????????????????Toast.makeText(context.getActivity(),"您沒有授權存儲權限,請在設置中打開授權", Toast.LENGTH_SHORT).show();
????????????????????????????????????}
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?});
????????????????????????????}
????????????????????});
????????????//取消
? ? ????????cancle.setOnClickListener(new View.OnClickListener() {
????????????????????????@Override
? ? ? ? ????????????????public void onClick(View v) {
????????????????????????????????dialog.dismiss();
????????????????????????}
? ? ? ? ? ? ? ?});
????dialog.show();
?}
? ? ? ? ?其中需要注意的是Android6.0動態權限適配。如果選擇相冊方式,需要判斷存儲權限;如果選擇相機方式,需要判斷相機以及存儲權限。我這里采用的是第三方庫RxPermissions
第二步:調用系統相冊或相機
1.調用相機
? ??????Intent intent =new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
????????//存放拍照的圖片文件
? ? ? ? if (!cameraFile.getParentFile().exists()){
????????cameraFile.getParentFile().mkdirs();
????????}
????????if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){
????????intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
????????Uri uri = FileProvider.getUriForFile(mContext.getActivity(),"com.xx.xxxxxi.fileprovider",cameraFile);
????????intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
????????}else{
????????????intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(cameraFile));
? ? ? ?}
? ? ? ?mContext.startActivityForResult(intent,FROM_CAMERA);
2.調用系統相冊
? ??Intent intent =new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
????intent.setType("image/*");
????mContext.startActivityForResult(intent,FROM_GALLERY);
第三步:界面中處理onActivityResult返回結果
? ??????switch (requestCode) {
????????????case FROM_GALLERY:
????????????????//裁剪圖片
? ? ? ????? ????PhotoUtils.getInstance().startCropImage(data.getData());
????????????????break;
????????????case FROM_CAMERA:
????????????????//裁剪圖片
? ? ? ? ????????if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){
????????????????????PhotoUtils.getInstance().startCropImage(FileProvider.getUriForFile(mContext,"com.xx.xxxx.fileprovider",cameraFile));
? ? ? ? ? ? ? ?}else{
????????????????????PhotoUtils.getInstance().startCropImage(Uri.fromFile(cameraFile));
????????????????}
????????????????break;
? ? ? ? ? ?case IMAGE_CROP:
????????????????Uri outputUri = Uri.parse("file://" +"/" + Constants.FILE_HEAD_PATH_CROP);
????????????????mPhotoFile =new File(Constants.FILE_HEAD_PATH_CROP);
????????????????//保存裁剪后的圖片
? ? ? ? ????????PhotoUtils.getInstance().saveImage(mPhotoFile,outputUri);
????????????????showLoading();
????????????????mPresenter.uploadHead(PreManager.instance().getString("token"),"image",mPhotoFile);//上傳圖片
? ? ? ????????? break;
這部分中,需要注意的是選擇相冊,返回的是uri路徑;而選擇相冊,我們是保存到文件中,所以需要通過保存的文件獲取到uri,但也要考慮到Android6.0權限問題,需要通過FileProvider.getUriForFile(mContext,"com.xx.xxxx.fileprovider",cameraFile)的方式獲取到uri
第四步:裁剪圖片
? ??public void startCropImage(Uri uri){
????????????Uri imageUri = uri;
????????????outputUri = Uri.parse("file://" +"/" + Constants.FILE_HEAD_PATH_CROP);//裁剪輸出文件
? ????????? Intent intent =new Intent("com.android.camera.action.CROP");
????????????if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){
????????????????????intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
????????????}
????????????intent.setDataAndType(imageUri,"image/*");
????????????intent.putExtra("crop","true");
????????????//設置寬高比例
? ????????? intent.putExtra("aspectX",1);
????????????intent.putExtra("aspectY",1);
? ? ? ? ? ? intent.putExtra("outputX",300);
????????????intent.putExtra("outputY",300);
? ? ? ? ? ? intent.putExtra(MediaStore.EXTRA_OUTPUT,outputUri);
????????????intent.putExtra("return-data",false);
? ? ? ? ? ? intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
????????????intent.putExtra("noFaceDetection",true);
????????????mContext.startActivityForResult(intent,IMAGE_CROP);
????????}
第五步:保存以及壓縮上傳
????????//保存裁剪后的圖片
????????public void saveImage(File file,Uri uri) {
????????????????//根據路徑獲取到原圖
? ? ????????????String realFilePath = getRealFilePath(uri);
????????????????Bitmap bitmap = BitmapFactory.decodeFile(realFilePath);
????????????????/*保存圖片*/
? ? ????????????ByteArrayOutputStream baos =new ByteArrayOutputStream();
????????????????// 把壓縮后的數據存放到baos中,壓縮質量為50%
? ? ????????????bitmap.compress(Bitmap.CompressFormat.JPEG,50, baos);
????????????????try {
????????????????????FileOutputStream fos =new FileOutputStream(file);
????????????????????fos.write(baos.toByteArray());
????????????????????fos.flush();
????????????????????fos.close();
????????????}catch (Exception e) {
????????????????????e.printStackTrace();
????????????}
????????}