拍照、本地图片工具类:解决了4.4以上剪裁会提示“找不到文件”和6.0动态授予权限,及7.0报FileUriExposedException异常问题。
package com.hb.weex.util; import android.Manifest; import android.app.Activity; import android.app.Dialog; import android.content.ClipData; import android.content.ContentUris; import android.content.ContentValues; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.net.Uri; import android.os.Build; import android.os.Environment; import android.provider.MediaStore; import android.support.v4.app.FragmentActivity; import android.support.v4.content.FileProvider; import android.view.View; import android.widget.Button; import com.hb.common.android.util.Log; import com.hb.weex.R; import com.hb.weex.util.ToastUtil; import com.hb.weex.util.UploadAvatarUtil; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Iterator; import java.util.List; import kr.co.namee.permissiongen.GrantPermissionActivity; import kr.co.namee.permissiongen.PermissionGen; import kr.co.namee.permissiongen.internal.Utils; /** * 拍照管理的类 * Created by cjy on 2017/4/03. */ public class TakePhotoManager implements View.OnClickListener,GrantPermissionActivity.OnGrantedListener { /** * 权限列表:写权限 读权限 调用摄像头权限 */ private static final String[] PERMISSIONS = new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE,Manifest.permission.CAMERA}; /* 上下文 */ private Activity context; /* 对话框 */ private Dialog mSelectPhotoDialog; /* 图片的存储地址-父路径 */ private String mHeadImageFileParentPath = ""; /* 照相机拍照后的照片 */ private String mCameraImageFileName = ""; /* 头像名称 */ private String mHeadImageFileName = ""; private Button mBtnTakePhoto;//拍照 private Button mBtnPickPhoto;//选择本地图片 private Button mBtnCancel;//取消 private Uri imageUri;//原图保存地址 public TakePhotoManager(Activity context) { this.context = context; mHeadImageFileParentPath = Environment.getExternalStorageDirectory() + File.separator+ context.getPackageName()+File.separator; mCameraImageFileName = "temp_camera_image.jpg"; mHeadImageFileName = "tmp_head_image.jpg"; } public void setmHeadImageFileParentPath(String mHeadImageFileParentPath) { this.mHeadImageFileParentPath = mHeadImageFileParentPath; } public void setmCameraImageFileName(String mCameraImageFileName) { this.mCameraImageFileName = mCameraImageFileName; } public void setmHeadImageFileName(String mHeadImageFileName) { this.mHeadImageFileName = mHeadImageFileName; } /** * 显示头像弹出窗 */ public void showSelectPhotoDialog() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {//23 //Android6.0及以上,需要动态授予权限 // 验证所有权限是否都已经授权了 List<String> deniedPermissions = Utils.findDeniedPermissions(this.context, PERMISSIONS); if (deniedPermissions.size() == 0) { showDialog(); } else { Intent intent = new Intent(this.context, GrantPermissionActivity.class); intent.putExtra(GrantPermissionActivity.PARAM_PERMISSION_NAME_LIST, PERMISSIONS); GrantPermissionActivity.mGrantedListener = this; this.context.startActivity(intent); } }else{ showDialog(); } } private void showDialog(){ View view = context.getLayoutInflater().inflate(R.layout.dlg_select_photo, null); mBtnTakePhoto = (Button) view.findViewById(R.id.btn_take_photo); mBtnPickPhoto = (Button) view.findViewById(R.id.btn_pick_photo); mBtnCancel = (Button) view.findViewById(R.id.btn_cancel); mBtnTakePhoto.setOnClickListener(this); mBtnPickPhoto.setOnClickListener(this); mBtnCancel.setOnClickListener(this); mSelectPhotoDialog = UploadAvatarUtil.createDialog(context, view, R.style.transparentFrameWindowStyle, R.style.select_photo_dialog_animstyle); } /** * 关闭头像弹出窗 */ public void hideSelectPhotoDialog() { if (mSelectPhotoDialog != null && mSelectPhotoDialog.isShowing()) { mSelectPhotoDialog.dismiss(); } } /** * 拍照 */ public void takePhoto(Activity context, String imgUrl, String imageFileNameTemp) { File file = UploadAvatarUtil.getFile(imgUrl, imageFileNameTemp); // 打开相机 Intent intentFromCapture = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { //FileUriExposedException这个异常只会在Android 7.0 + 出现,当app使用file:// url 共享给其他app时, 会抛出这个异常。 //因为在android 6.0 + 权限需要 在运行时候检查, 其他app 可能没有读写文件的权限, 所以google在7.0的时候加上了这个限制。官方推荐使用 FileProvider 解决这个问题。 intentFromCapture.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION ); //添加这一句表示对目标应用临时授权该Uri所代表的文件 imageUri = FileProvider.getUriForFile(context, "com.hb.weex.accountant.fileprovider", file);//通过FileProvider创建一个content类型的Uri } else { imageUri = Uri.fromFile(file); } intentFromCapture.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);//将拍取的照片保存到指定URI context.startActivityForResult(intentFromCapture, UploadAvatarUtil.CAMERA_REQUEST_CODE); } /** * 选择本地图片 */ public void pickPhoto(Activity context) { Intent intent = new Intent(Intent.ACTION_PICK); intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*"); context.startActivityForResult(intent, UploadAvatarUtil.IMAGE_REQUEST_CODE); } public Object onActivityResult(Context context,int requestCode, int resultCode, Intent data) { //关闭头像弹出窗 hideSelectPhotoDialog(); if (resultCode != Activity.RESULT_CANCELED) { switch (requestCode) { case UploadAvatarUtil.IMAGE_REQUEST_CODE:// 选择本地图片返回 if (null != data) {//为了取消选取不报空指针用的 imageUri = data.getData(); startPhotoZoom(context, imageUri , 1); } break; case UploadAvatarUtil.CAMERA_REQUEST_CODE:// 拍照返回 if (UploadAvatarUtil.hasSdcard()) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {//24 startPhotoZoom(context, imageUri, 0); }else{ File tempFile = getFileTmp(); startPhotoZoom(context, Uri.fromFile(tempFile), 0); } } else { ToastUtil.showToast(context, context.getResources().getString(R.string.find_sdcard_none)); } break; case UploadAvatarUtil.CLIP_REQUEST_CODE:// 裁剪完成,删除照相机缓存的图片 Bitmap imageBitmap = null; //获取头像文件 File file = getTmpHeadImage(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){//24 try { imageBitmap = BitmapFactory.decodeStream(context.getContentResolver().openInputStream(imageUri)); } catch (FileNotFoundException e) { e.printStackTrace(); } }else { if (!file.exists()) { return null; } imageBitmap = BitmapFactory.decodeFile(file.getAbsolutePath()); } if (imageBitmap == null) { return null; } ByteArrayOutputStream baos = new ByteArrayOutputStream(); imageBitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos); byte[] userImageData = baos.toByteArray(); //修改个人头像 HashMap<String, Object> result = new HashMap<String, Object>(); if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) { result.put("path", file.getAbsolutePath()); } result.put("data",userImageData); return result; } } return null; } /** * 裁剪图片 * * @param uri from 1代表本地照片的裁剪,0代表拍照后的裁剪 */ public void startPhotoZoom(Context context, Uri uri, int from) { Intent intent = new Intent("com.android.camera.action.CROP"); String url = convertPath(context, uri); /** * 当满足:SDK>4.0、选择本地照片操作、裁剪框为圆形(或者说路径与之前版本有异)三个条件时 * 进行转换操作 */ if (Build.VERSION.SDK_INT >= 19 && from == 1 && url != null) { intent.setDataAndType(Uri.fromFile(new File(url)), "image/*"); } else { intent.setDataAndType(uri, "image/*"); } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION ); } // 设置裁剪 intent.putExtra("crop", "true"); // aspectX aspectY 是宽高的比例 intent.putExtra("aspectX", 1); intent.putExtra("aspectY", 1); // outputX outputY 是裁剪图片宽高 intent.putExtra("outputX", 100); intent.putExtra("outputY", 100); Uri uriPath; if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {//小于24 uriPath = Uri.fromFile(UploadAvatarUtil.getFile(mHeadImageFileParentPath, mHeadImageFileName)); }else{ uriPath = imageUri; } intent.putExtra(MediaStore.EXTRA_OUTPUT, uriPath); intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString()); intent.putExtra("return-data", false); //intent.putExtra("return-data", true); //return-data为true时,会直接返回bitmap数据,但是大图裁剪时会出现问题。 //设置为false比较好,但是,需要指定MediaStore.EXTRA_OUTPUT,来保存裁剪之后的图片 ((Activity)context).startActivityForResult(intent, UploadAvatarUtil.CLIP_REQUEST_CODE); } /** * 删除缓存的头像 */ public void deleteHeadCache() { UploadAvatarUtil.deleteLocalImage(mHeadImageFileParentPath, mHeadImageFileName); } /** * 获取文件对象---照相机拍照的 * * @return */ public File getFileTmp() { return UploadAvatarUtil.getFile(mHeadImageFileParentPath, mCameraImageFileName); } /** * 获取裁剪之后的图片文件 */ public File getTmpHeadImage(){ return UploadAvatarUtil.getFile(mHeadImageFileParentPath,mHeadImageFileName); } /** * 删除照相机拍照的图片 */ public void deleteCameraImage() { UploadAvatarUtil.deleteLocalImage(mHeadImageFileParentPath, mCameraImageFileName); } @Override public void onClick(View view) { switch (view.getId()) { case R.id.btn_take_photo: takePhoto(context, mHeadImageFileParentPath, mCameraImageFileName); break; case R.id.btn_pick_photo: pickPhoto(context); break; case R.id.btn_cancel: hideSelectPhotoDialog(); break; } } /** * 将uri转换成字符串 * 解决4.4版本以上获取到的uri是图片名称而非图片路径,导致剪裁图片时提示无法加载图片的问题 * 详细的解决方案,请参考这篇文章 * 当安卓的版本比较高时(如4.4),选择本地相册可能会返回“无法加载此图片” * 原因:正常uri是file://...而高版本是content://... * 所以需要一个转换操作 * * @param context * @param uri * @return */ public String convertPath(final Context context, final Uri uri) { //代表SDK4.4需要反射的类 Class getClass = null; //代表两个SDK4.4里面反射的方法 Method isMethod; Method getMethod; String stringMethod = ""; //判断当前版本是否大于4.0 final boolean isKitKat = Build.VERSION.SDK_INT >= 19; try { /** * 获取类和方法 * 方法传参方式 * 获取返回值 */ getClass = Class.forName("android.provider.DocumentsContract"); getMethod = getClass.getMethod("getDocumentId", new Class[]{Uri.class}); isMethod = getClass.getMethod("isDocumentUri", new Class[]{Context.class, Uri.class}); Object isResult = isMethod.invoke(getClass, new Object[]{context, uri}); Object getResult = getMethod.invoke(getClass, new Object[]{uri}); stringMethod = (String) getResult; if (!(Boolean) isResult) return null; //当手机SDK大于4.4且路径类型与以往不同时(isShot为True时往往裁剪框是圆形,即是新类型的路径) if (isKitKat) { if (isExternalStorageDocument(uri)) { final String docId = stringMethod; final String[] split = docId.split(":"); final String type = split[0]; if ("primary".equalsIgnoreCase(type)) { return Environment.getExternalStorageDirectory() + "/" + split[1]; } } else if (isDownloadsDocument(uri)) { final String id = stringMethod; final Uri contentUri = ContentUris.withAppendedId( //高版本的路径不同于低版本,需要转换 Uri.parse("content://downloads/public_downloads"), Long.valueOf(id)); return getDataColumn(context, contentUri, null, null); } else if (isMediaDocument(uri)) { final String docId = stringMethod; final String[] split = docId.split(":"); final String type = split[0]; Uri contentUri = null; if ("image".equals(type)) { contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; } else if ("video".equals(type)) { contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI; } else if ("audio".equals(type)) { contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI; } final String selection = "_id=?"; final String[] selectionArgs = new String[]{ split[1] }; return getDataColumn(context, contentUri, selection, selectionArgs); } } else if ("content".equalsIgnoreCase(uri.getScheme())) { if (isGooglePhotosUri(uri)) return uri.getLastPathSegment(); return getDataColumn(context, uri, null, null); } else if ("file".equalsIgnoreCase(uri.getScheme())) { return uri.getPath(); } return null; } catch (Exception e) { Log.e("error", e.toString()); } return null; } //获取String类型的路径 public static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) { Cursor cursor = null; final String column = "_data"; final String[] projection = { column }; try { cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null); if (cursor != null && cursor.moveToFirst()) { final int index = cursor.getColumnIndexOrThrow(column); return cursor.getString(index); } } finally { if (cursor != null) cursor.close(); } return null; } public static boolean isExternalStorageDocument(Uri uri) { return "com.android.externalstorage.documents".equals(uri.getAuthority()); } public static boolean isDownloadsDocument(Uri uri) { return "com.android.providers.downloads.documents".equals(uri.getAuthority()); } public static boolean isMediaDocument(Uri uri) { return "com.android.providers.media.documents".equals(uri.getAuthority()); } public static boolean isGooglePhotosUri(Uri uri) { return "com.google.android.apps.photos.content".equals(uri.getAuthority()); } @Override public void onGrantSuccess() { showDialog(); } }
在7.0 上使用FileProvider来获取图片的路径,需要以下几步设置:
(1)在Androidmainfest的Application根标签中设置provider,相机,读写文件权限
<!-- Android7.0以上,拍照需要设置FileProvider --> <provider android:name="android.support.v4.content.FileProvider" android:authorities="com.hb.accountant.accountant.fileprovider" android:grantUriPermissions="true" android:exported="false"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> </provider>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.CAMERA"/>
(2)在res/xml目录中创建文件file_paths.xml:
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <!--external-path 就是用来指定URI共享的 name属性的值可以随便写 path属性的值表示共享的具体位置,设置空就表示将整个SD卡进行共享 用该路径保存的好处是,文件会随着应用的卸载而删除,file/header/为自定义路径 Android/data/com.bugull.cameratakedemo/files/header/ --> <!--<external-path name = "my-images" path = "demo"/>--> <paths> <external-path path="包名" name="camera_photos" /> </paths> </paths>
注:文件中涉及的其他文件如下:
(1)动态权限授权使用第三方PermissionGen
(2)UploadAvatarUtil.java
package com.hb.weex.util; import android.app.Activity; import android.app.Dialog; import android.content.Context; import android.content.Intent; import android.graphics.*; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.LayerDrawable; import android.net.Uri; import android.os.Environment; import android.provider.MediaStore; import android.view.View; import android.view.ViewGroup; import android.view.Window; import android.view.WindowManager; import com.hb.common.android.util.Log; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; /** * 上传用户头像 * 功能如下: * 1、保存图片到本地、删除本地图片 * 2、拍照、从图库中选择照片、剪裁 * 3、创建文件目录、获取文件对象 * 4、检查Sdcard是否存在 * 5、创建圆角矩形图片 * 6、创建圆角图片 * 7、自定义从下往上显示的Dialog(模仿QQ退出效果) * 8、图片上绘制文字 * Created by cjy on 2015/4/9. */ public class UploadAvatarUtil { public static final int IMAGE_REQUEST_CODE = 0; //选择本地图片 public static final int CAMERA_REQUEST_CODE = 1; //拍照 public static final int CLIP_REQUEST_CODE = 2; //裁剪 private static final int DEFAULT_TEXT_SIZE = 32;//默认的字体大小 /** * 检查是否存在sdcard * * @return */ public static boolean hasSdcard() { String state = Environment.getExternalStorageState(); if (state.equals(Environment.MEDIA_MOUNTED)) { return true; } else { return false; } } /** * 创建文件目录 * * @param filePath 文件路径 */ public static File makeFileDir(String filePath) { File file = null; try { file = new File(filePath); if (!file.exists()) { file.mkdirs(); } } catch (Exception e) { e.printStackTrace(); } return file; } /** * 获取文件对象 * * @param filePath 文件路径 * @param fileName 文件名称 * @return */ public static File getFile(String filePath, String fileName) { File file = null; //创建文件目录 makeFileDir(filePath); try { file = new File(filePath + fileName); } catch (Exception e) { e.printStackTrace(); } return file; } /** * 保存图片到本地 * * @param imgUrl 图片路径 * @param imageFileName 图片名称 * @param bitmap */ public static void saveLocalImage(String imgUrl, String imageFileName, Bitmap bitmap) { try { File f = getFile(imgUrl, imageFileName); FileOutputStream fOut = new FileOutputStream(f); bitmap.compress(Bitmap.CompressFormat.PNG, 100, fOut); fOut.flush(); fOut.close(); } catch (IOException e) { e.printStackTrace(); } } /** * 删除本地图片 * * @param imgUrl 图片路径 * @param imageFileName 图片名称 */ public static void deleteLocalImage(String imgUrl, String imageFileName) { File f = getFile(imgUrl, imageFileName); if (f.isFile() && f.exists()) { f.delete(); } } /** * 绘制圆角矩形图片 * 圆形 x=120,y=120,outerRadiusRat=60 * * @param x * @param y * @param image * @param outerRadiusRat * @return */ public static Bitmap createFramedPhoto(int x, int y, Bitmap image, float outerRadiusRat) { // 根据源文件新建一个darwable对象 Drawable imageDrawable = new BitmapDrawable(image); // 新建一个新的输出图片 Bitmap output = Bitmap.createBitmap(x, y, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(output); // 新建一个矩形 RectF outerRect = new RectF(0, 0, x, y); // 产生一个白色的圆角矩形 Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); paint.setColor(Color.RED); canvas.drawRoundRect(outerRect, outerRadiusRat, outerRadiusRat, paint); // 将源图片绘制到这个圆角矩形上 paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); imageDrawable.setBounds(0, 0, x, y); canvas.saveLayer(outerRect, paint, Canvas.ALL_SAVE_FLAG); imageDrawable.draw(canvas); canvas.restore(); return output; } /** * 选择本地图片 */ public static void pickPhoto(Context context) { Intent intentFromGallery = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); intentFromGallery.setType("image/*"); // 设置文件类型 intentFromGallery.setAction(Intent.ACTION_GET_CONTENT); ((Activity) context).startActivityForResult(intentFromGallery, IMAGE_REQUEST_CODE); } /** * 拍照 */ public static void takePhoto(Context context, String imgUrl, String imageFileNameTemp) { // 打开相机 Intent intentFromCapture = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); // 判断存储卡是否可以用,存储缓存图片 if (hasSdcard()) { intentFromCapture.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(getFile(imgUrl, imageFileNameTemp))); } ((Activity) context).startActivityForResult(intentFromCapture, CAMERA_REQUEST_CODE); } /** * 裁剪图片 * * @param uri */ public static void startPhotoZoom(Context context, Uri uri) { Intent intent = new Intent("com.android.camera.action.CROP"); intent.setDataAndType(uri, "image/*"); // 设置裁剪 intent.putExtra("crop", "true"); // aspectX aspectY 是宽高的比例 intent.putExtra("aspectX", 1); intent.putExtra("aspectY", 1); // outputX outputY 是裁剪图片宽高 intent.putExtra("outputX", 200); intent.putExtra("outputY", 200); intent.putExtra("return-data", true); // intent.putExtra(MediaStore.EXTRA_OUTPUT, uri); // intent.putExtra("return-data", false);//设置为不返回数据 ((Activity) context).startActivityForResult(intent, CLIP_REQUEST_CODE); } /** * 创建指定样式、指定动画的Dialog * * @param context * @param view Dialog的布局 * @param styleId Dialog的样式 * @param animStyleId Dialog的动画样式 * @return */ public static Dialog createDialog(Context context, View view, int styleId, int animStyleId) { Dialog mSelectPhotoDialog = new Dialog(context, styleId); mSelectPhotoDialog.setContentView(view); Window window = mSelectPhotoDialog.getWindow(); // 设置显示动画 window.setWindowAnimations(animStyleId); WindowManager.LayoutParams wl = window.getAttributes(); wl.x = 0; wl.y = ((Activity) context).getWindowManager().getDefaultDisplay().getHeight(); // 以下这两句是为了保证按钮可以水平满屏 wl.width = ViewGroup.LayoutParams.MATCH_PARENT; wl.height = ViewGroup.LayoutParams.WRAP_CONTENT; // 设置显示位置 mSelectPhotoDialog.onWindowAttributesChanged(wl); // 设置点击外围解散 mSelectPhotoDialog.setCanceledOnTouchOutside(true); mSelectPhotoDialog.show(); return mSelectPhotoDialog; } /** * 第1种方法:图片上绘制文字 * * @param context * @param drawableId * @param text * @param color * @return */ public static Bitmap drawTextAtBitmap(Context context, int drawableId, String text, int color, float density) { Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), drawableId); int[] size = getBitmapSize(context, drawableId); // Log.e("density", density + ""); int x = size[0]; int y = size[1]; // int x = (int) (size[0] * density); // int y = (int) (size[1] * density); // Log.e("x", x + ""); // Log.e("y", y + ""); // bitmap = getScaleBitmap(context,bitmap); // 创建一个和原图同样大小的位图 Bitmap newbit = Bitmap.createBitmap(x, y, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(newbit); Paint paint = new Paint(); // 贴图 在原始位置0,0插入原图 canvas.drawBitmap(bitmap, 0, 0, paint); paint.setColor(color); int textSize = DEFAULT_TEXT_SIZE; if (density >= 3) { textSize *= (density + 1); } else if (density >= 2) { textSize *= (density + 0.1); } paint.setTextSize(textSize); paint.setTextAlign(Paint.Align.CENTER); // 在原图指定位置写上字 // canvas.drawText(text, x / 2 - 10 * density, y / 2, paint); canvas.drawText(text, x / 2, y / 2 + 20 * (density-1) + 2, paint); canvas.save(Canvas.ALL_SAVE_FLAG); // 存储 canvas.restore(); return newbit; } /** * 图片叠加 * * @param bitmap1 * @param bitmap2 * @return */ public static Bitmap layerBitmap(Bitmap bitmap1, Bitmap bitmap2) { // copy 防止出现Immutable bitmap passed to Canvas constructor错误 bitmap1 = bitmap1.copy(Bitmap.Config.ARGB_8888, true); Bitmap newBitmap = null; newBitmap = Bitmap.createBitmap(bitmap1); Canvas canvas = new Canvas(newBitmap); Paint paint = new Paint(); int w = bitmap1.getWidth(); int h = bitmap1.getHeight(); int w_2 = bitmap2.getWidth(); int h_2 = bitmap2.getHeight(); paint.setColor(Color.GRAY); paint.setAlpha(125); canvas.drawRect(0, 0, bitmap1.getWidth(), bitmap1.getHeight(), paint); paint = new Paint(); canvas.drawBitmap(bitmap2, Math.abs(w - w_2) / 2, Math.abs(h - h_2) / 2, paint); canvas.save(Canvas.ALL_SAVE_FLAG); // 存储新合成的图片 canvas.restore(); return newBitmap; } /** * 图片叠加 * * @param bitmap1 * @param bitmap2 * @return */ public static LayerDrawable layerDrawable(Bitmap bitmap1, Bitmap bitmap2) { Drawable[] array = new Drawable[2]; array[0] = new BitmapDrawable(bitmap1); array[1] = new BitmapDrawable(bitmap2); LayerDrawable la = new LayerDrawable(array); // 其中第一个参数为层的索引号,后面的四个参数分别为left、top、right和bottom la.setLayerInset(0, 0, 0, 0, 0); la.setLayerInset(1, 10, 10, 10, 10); return la; } /** * 获取Bitmap的宽高 * * @param context * @param drawableId 图片id * @return */ private static int[] getBitmapSize(Context context, int drawableId) { int[] size = new int[2]; BitmapFactory.Options opts = new BitmapFactory.Options(); opts.inJustDecodeBounds = true; BitmapFactory.decodeResource(context.getResources(), drawableId, opts); int width = opts.outWidth; int height = opts.outHeight; size[0] = width; size[1] = height; return size; } /** * 等比例缩放 * * @param context * @param bitmap * @return */ public static Bitmap getScaleBitmap(Context context, Bitmap bitmap) { int[] screen = ScreenPixelsUtil.getScreenPixels(context); Matrix matrix = new Matrix(); int width = bitmap.getWidth(); int height = bitmap.getHeight(); Log.e("Width", width + ""); Log.e("Height", height + ""); //屏幕宽度/图片宽度 float w = screen[0] / width; float h = screen[1] / height; matrix.postScale(w, h);// 获取缩放比例 // 根据缩放比例获取新的位图 Bitmap newbmp = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true); return newbmp; } }
(3)资源文件:
dlg_select_photo.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/pop_layout" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/transparent" android:gravity="bottom" android:layout_gravity="center_horizontal" android:paddingLeft="10dp" android:paddingRight="10dp" android:paddingBottom="10dp" > <LinearLayout android:orientation="vertical" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@drawable/setting_dialog" > <Button android:id="@+id/btn_take_photo" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/take_photo" android:paddingTop="14dp" android:paddingBottom="14dp" android:layout_marginTop="2dp" android:layout_marginLeft="4dp" android:layout_marginRight="4dp" android:textSize="17dp" android:textColor="#333333" android:background="@color/white"/> <View android:layout_width="match_parent" android:layout_height="0.5dp" android:background="@color/dropdownmenu_line"/> <Button android:id="@+id/btn_pick_photo" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/pick_photo" android:paddingTop="14dp" android:paddingBottom="14dp" android:layout_marginLeft="4dp" android:layout_marginRight="4dp" android:textSize="17dp" android:textColor="#333333" android:background="@color/white"/> </LinearLayout> <Button android:id="@+id/btn_cancel" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="取消" android:paddingTop="14dp" android:paddingBottom="14dp" android:textSize="17dp" android:textColor="@color/gray" android:background="@drawable/setting_dialog" android:layout_marginTop="16dp"/> </LinearLayout>
styles.xml
<!-- 头像弹出窗的动画效果 --> <style name="select_photo_dialog_animstyle"> <item name="android:windowEnterAnimation">@anim/photo_dialog_in_anim</item> <item name="android:windowExitAnimation">@anim/photo_dialog_out_anim</item> </style>
drawable
//photo_dialog_in_anim.xml <?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android" > <translate android:duration="500" android:fromXDelta="0" android:fromYDelta="1000" android:toXDelta="0" android:toYDelta="0" /> </set> //photo_dialog_out_anim.xml <?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android" > <translate android:duration="500" android:fromXDelta="0" android:fromYDelta="0" android:toXDelta="0" android:toYDelta="1000" /> </set>