> 文章列表 > Android修改头像之拍照、从相册选择、裁剪

Android修改头像之拍照、从相册选择、裁剪

Android修改头像之拍照、从相册选择、裁剪

手写一个修改头像的需求,头像图片支持手机拍照裁剪和从相册选择图片裁剪;

实现效果:

 本节主要内容:

1)头像修改对话框实现;

2)调用系统相机拍照;

3)自定义图片裁剪页面;

4)从系统相册选择图片。

一、头像修改对话框实现

很简单的一个对话框

class HeadChangeDialog(context: Context) : Dialog(context, R.style.BottomDialog), View.OnClickListener {var onHeadChangeListener: OnHeadChangeListener? = nullinit {this.init()}fun init() {val contentView = LayoutInflater.from(context).inflate(R.layout.dialog_sdk_head_change, null)setContentView(contentView)val params = contentView.layoutParams as ViewGroup.MarginLayoutParamsparams.width = context.resources.displayMetrics.widthPixels - DensityUtil.dp2px(context, 0f)params.bottomMargin = DensityUtil.dp2px(context, 0f)contentView.layoutParams = paramssetCanceledOnTouchOutside(true)window?.setGravity(Gravity.BOTTOM)window?.setWindowAnimations(R.style.BottomDialog_Animation)// 设置点击事件contentView.findViewById<TextView>(R.id.tv_camera).setOnClickListener(this)contentView.findViewById<TextView>(R.id.tv_photo).setOnClickListener(this)contentView.findViewById<TextView>(R.id.tv_cancel).setOnClickListener(this)}override fun onClick(v: View?) {when (v!!.id) {R.id.tv_camera -> {onHeadChangeListener?.onCamera()dismiss()}R.id.tv_photo -> {onHeadChangeListener?.onPhoto()dismiss()}R.id.tv_cancel -> dismiss()}}interface OnHeadChangeListener {fun onCamera()fun onPhoto()}
}

二、调用系统相机拍照

1)动态申请权限

private void toCamera() {// 判断是否需要动态申请存储权限if (!PermissionUtil.checksCameraPermission(this)) {DialogManager.getInstance().showDialog(getString(R.string.camera_tip1), this, () -> {if (PermissionUtil.deniedPermission()) {// 用户已拒绝权限,跳转系统设置页Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).setData(Uri.fromParts("package", getPackageName(), null));intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);startActivity(intent);overridePendingTransition(R.anim.slide_in_right, R.anim.slide_out_left);} else {// 用户未拒绝权限,弹框动态申请权限PermissionUtil.requestCameraPermission(this);}});return;}startCamera();
}

2)调用系统相机拍照

在设置Uri是要注意,Android7.0及以上系统禁止应用向外部公开file://URI ,因此需要FileProvider来向外界传递URI。

public void takePicture(Activity activity, int requestCode) {try {Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);takePictureIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);if (FileUtil.existSDCard()) {takeImageFile = new File(Environment.getExternalStorageDirectory(), "/DCIM/camera/");} else {takeImageFile = Environment.getDataDirectory();}takeImageFile = createFile(takeImageFile, "IMG_", ".jpg");if (takeImageFile != null) {// 默认情况下,即不需要指定intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);// 照相机有自己默认的存储路径,拍摄的照片将返回一个缩略图。如果想访问原始图片,// 可以通过dat extra能够得到原始图片位置。即,如果指定了目标uri,data就没有数据,// 如果没有指定uri,则data就返回有数据!Uri uri;if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M) {uri = Uri.fromFile(takeImageFile);} else {/*** 7.0 调用系统相机拍照不再允许使用Uri方式,应该替换为FileProvider* 并且这样可以解决MIUI系统上拍照返回size为0的情况*/uri = FileProvider.getUriForFile(activity, ProviderUtil.getFileProviderName(activity), takeImageFile);//加入uri权限 要不三星手机不能拍照List<ResolveInfo> resInfoList = activity.getPackageManager().queryIntentActivities(takePictureIntent, PackageManager.MATCH_DEFAULT_ONLY);for (ResolveInfo resolveInfo : resInfoList) {String packageName = resolveInfo.activityInfo.packageName;activity.grantUriPermission(packageName, uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);}}LogUtil.i(TAG, ProviderUtil.getFileProviderName(activity));takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, uri);}activity.startActivityForResult(takePictureIntent, requestCode);} catch (Exception e) {e.printStackTrace();}
}

3)自定义FileProvider

FileProvider是ContentProvider的一个子类,用于应用程序之间私有文件的传递。自Android 7.0后系统禁止应用向外部公开file://URI ,因此需要FileProvider来向外界传递URI,传递的形式是content : //Uri,使用时需要在清单文件中注册。

// 自定义一个Provider,以免和引入的项目的provider冲突
public class ImagePickerProvider extends FileProvider {
}

注册清单文件

<providerandroid:name=".image.ImagePickerProvider"android:authorities="${applicationId}.provider"android:exported="false"android:grantUriPermissions="true"><meta-dataandroid:name="android.support.FILE_PROVIDER_PATHS"android:resource="@xml/provider_paths"/>
</provider>

创建provider_paths.xml文件

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android"><external-path name="external_files" path="."/>
</paths>

4)获取相机拍照图片路径,裁剪图片

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {if (resultCode == RESULT_OK) {switch (requestCode) {case ImagePicker.REQUEST_CODE_TAKE:String imagePath = ImagePicker.getInstance().getTakeImageFile().getAbsolutePath();LogUtil.i(TAG, "startCamera imagePath " + imagePath);if (!TextUtils.isEmpty(imagePath)) {Intent intent = new Intent(mContext, CorpImgActivity.class);intent.putExtra(Constants.IMAGE_PATH, imagePath);startActivityForResult(intent, ImagePicker.REQUEST_CODE_CROP);}break;}}super.onActivityResult(requestCode, resultCode, data);
}

三、自定义图片裁剪页面

图片裁剪页面功能实现:

1)显示图片

private void initData() {Bundle bundle = getIntent().getExtras();if (bundle != null && bundle.containsKey(Constants.IMAGE_URI)) {Uri imageUri = (Uri) bundle.get(Constants.IMAGE_URI);if (imageUri != null) {try {// 要裁剪的图片mCropBitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(imageUri));mCorpImg.setImageBitmap(mCropBitmap);} catch (FileNotFoundException e) {e.printStackTrace();}}}if (bundle != null && bundle.containsKey(Constants.IMAGE_PATH)) {String imagePath = (String) bundle.get(Constants.IMAGE_PATH);if (imagePath != null) {try {// 要裁剪的图片mCropBitmap = BitmapFactory.decodeStream(new FileInputStream(imagePath));// 旋转图片int degree = BitmapUtil.getBitmapDegree(imagePath);LogUtil.i(TAG, "degree " + degree);if (degree != 0)mCropBitmap = BitmapUtil.rotateBitmapByDegree(mCropBitmap, degree);mCorpImg.setImageBitmap(mCropBitmap);} catch (FileNotFoundException e) {e.printStackTrace();}}}
}

2)实现拖拽图片

mCorpImg.setOnTouchListener(new View.OnTouchListener() {@Overridepublic boolean onTouch(View view, MotionEvent motionEvent) {switch (motionEvent.getAction() ) {case MotionEvent.ACTION_DOWN:downX = motionEvent.getX();downY = motionEvent.getY();break;case MotionEvent.ACTION_MOVE:Matrix matrix = mCorpImg.getImageMatrix();//指定移动距离matrix.postTranslate(motionEvent.getX() - downX, motionEvent.getY() - downY);downX = motionEvent.getX();downY = motionEvent.getY();break;case MotionEvent.ACTION_UP:break;}mCorpImg.invalidate();return true;}
});

3)放大缩小图片

mCorpImg.setOnTouchListener(new View.OnTouchListener() {@Overridepublic boolean onTouch(View view, MotionEvent motionEvent) {switch (motionEvent.getAction() & motionEvent.getActionMasked()) {case MotionEvent.ACTION_POINTER_DOWN://次要点被点击oldSpacing = spacing(motionEvent);if (oldSpacing > 10f) {isPointer = false;isMain = false;state = ZOOM;midPoint(mid, motionEvent);}break;case MotionEvent.ACTION_POINTER_UP://次要点松开isPointer = true;if (isPointer && isMain) {isPointer = false;isMain = false;state = DRAG;oldSpacing = 1f;}break;case MotionEvent.ACTION_DOWN:downX = motionEvent.getX();downY = motionEvent.getY();break;case MotionEvent.ACTION_MOVE:Matrix matrix = mCorpImg.getImageMatrix();if (state == DRAG) {//拖拽matrix.postTranslate(motionEvent.getX() - downX, motionEvent.getY() - downY);downX = motionEvent.getX();downY = motionEvent.getY();} else if (state == ZOOM && !isPointer && !isMain) {//放大缩小float newSpacing = spacing(motionEvent);float scale = newSpacing / oldSpacing;matrix.postScale(scale, scale, mid.x, mid.y);oldSpacing = newSpacing;}break;case MotionEvent.ACTION_UP://用户多点触碰释放时,需要同时释放所有点才初始,防止发生偏移。isMain = true;if (isPointer && isMain) {isPointer = false;isMain = false;state = DRAG;oldSpacing = 1f;}break;}mCorpImg.invalidate();return true;}
});/*** 多点触控时,计算最先放下的两指距离** @param event* @return*/
private float spacing(MotionEvent event) {float x = event.getX(0) - event.getX(1);float y = event.getY(0) - event.getY(1);return (float) Math.sqrt(x * x + y * y);
}/*** 多点触控时,计算最先放下的两指中心坐标** @param point* @param event*/
private void midPoint(PointF point, MotionEvent event) {float x = event.getX(0) + event.getX(1);float y = event.getY(0) + event.getY(1);point.set(x / 2, y / 2);
}

4)保存裁剪框区域图片

@Override
public void onRightTopMenuClick() {super.onRightTopMenuClick();Bitmap bitmap = getBitmap();File file = FileUtil.createImageFile();file = BitmapUtil.compressImage(bitmap, file);mCropBitmap.recycle();mCropBitmap = null;Intent intent = new Intent();intent.putExtra(Constants.IMAGE_PATH, file.getPath());setResult(RESULT_OK, intent);finish();
}/*** 获取裁剪框内截图** @return*/
private Bitmap getBitmap() {// 获取截屏mCropLayout.setDrawingCacheEnabled(true);mCropLayout.buildDrawingCache();// 计算裁剪框的开始位置left = (mCropLayout.getWidth() - mCropView.getWidth()) / 2;top = (mCropLayout.getHeight() - mCropView.getHeight()) / 2;// 裁剪框的边框宽度int borderWidth = DensityUtil.dp2px(getContext(), 2.5f);Bitmap finalBitmap = Bitmap.createBitmap(mCropLayout.getDrawingCache(),left + borderWidth, top + borderWidth, mCropView.getWidth() - 2 * borderWidth,mCropView.getHeight() - 2 * borderWidth);// 释放资源mCropLayout.destroyDrawingCache();return finalBitmap;
}

四、从系统相册选择图片

1)动态申请权限

private void toChooseImg() {// 判断是否需要动态申请存储权限if (!PermissionUtil.checksStoragePermission(this)) {DialogManager.getInstance().showDialog(getString(R.string.storage_tip1), this, () -> {if (PermissionUtil.deniedStoragePermission()) {// 用户已拒绝权限,跳转系统设置页Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).setData(Uri.fromParts("package", getPackageName(), null));intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);startActivity(intent);overridePendingTransition(R.anim.slide_in_right, R.anim.slide_out_left);} else {// 用户未拒绝权限,弹框动态申请权限PermissionUtil.requestStoragePermission(this);}});return;}choosePhoto();
}

2)打开系统相册

public void photoAlbum(Activity activity, int requestCode) {Intent intentToPickPic = new Intent(Intent.ACTION_PICK, null);// 单个图片类型:"image/jpeg 、 image/png等的类型",所有类型:"image/*"intentToPickPic.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");activity.startActivityForResult(intentToPickPic, requestCode);
}

3)获取获取手机相册图片Uri,裁剪图片

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {if (resultCode == RESULT_OK) {switch (requestCode) {case ImagePicker.REQUEST_CODE_PICK:// 获取图片try {//该uri是上一个Activity返回的Uri imageUri = data.getData();LogUtil.i(TAG, "choosePhoto imageUri " + imageUri);if (imageUri != null) {Intent intent = new Intent(mContext, CorpImgActivity.class);intent.putExtra(Constants.IMAGE_URI, imageUri);startActivityForResult(intent, ImagePicker.REQUEST_CODE_CROP);}} catch (Exception e) {e.printStackTrace();}break;}}super.onActivityResult(requestCode, resultCode, data);
}

功能完成,测试手机Android6.0、7.0及以上系统版本的华为、小米、三星、谷歌手机暂未发现问题。

源码:

图片选择工具类

package com.lib.common.image;import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.MediaStore;import androidx.core.content.FileProvider;import com.lib.common.util.FileUtil;
import com.lib.common.util.LogUtil;import java.io.File;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.text.SimpleDateFormat;/*** @Author: Jin* @Description: 图片选择工具* @CreateDate: 2023/4/20  14:50*/
public class ImagePicker {private static final String TAG = "ImagePicker";public static final int REQUEST_CODE_TAKE = 1001; // 打开照相机public static final int REQUEST_CODE_CROP = 1002; // 图片裁剪public static final int REQUEST_CODE_PICK = 1003; // 打开相册private File takeImageFile;private static ImagePicker mInstance;private ImagePicker() {}public static ImagePicker getInstance() {if (mInstance == null) {synchronized (ImagePicker.class) {if (mInstance == null) {mInstance = new ImagePicker();}}}return mInstance;}public File getTakeImageFile() {return takeImageFile;}/*** 拍照的方法*/public void takePicture(Activity activity, int requestCode) {try {Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);takePictureIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);if (FileUtil.existSDCard()) {takeImageFile = new File(Environment.getExternalStorageDirectory(), "/DCIM/camera/");} else {takeImageFile = Environment.getDataDirectory();}takeImageFile = createFile(takeImageFile, "IMG_", ".jpg");if (takeImageFile != null) {// 默认情况下,即不需要指定intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);// 照相机有自己默认的存储路径,拍摄的照片将返回一个缩略图。如果想访问原始图片,// 可以通过dat extra能够得到原始图片位置。即,如果指定了目标uri,data就没有数据,// 如果没有指定uri,则data就返回有数据!Uri uri;if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M) {uri = Uri.fromFile(takeImageFile);} else {/*** 7.0 调用系统相机拍照不再允许使用Uri方式,应该替换为FileProvider* 并且这样可以解决MIUI系统上拍照返回size为0的情况*/uri = FileProvider.getUriForFile(activity, ProviderUtil.getFileProviderName(activity), takeImageFile);//加入uri权限 要不三星手机不能拍照List<ResolveInfo> resInfoList = activity.getPackageManager().queryIntentActivities(takePictureIntent, PackageManager.MATCH_DEFAULT_ONLY);for (ResolveInfo resolveInfo : resInfoList) {String packageName = resolveInfo.activityInfo.packageName;activity.grantUriPermission(packageName, uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);}}LogUtil.i(TAG, ProviderUtil.getFileProviderName(activity));takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, uri);}activity.startActivityForResult(takePictureIntent, requestCode);} catch (Exception e) {e.printStackTrace();}}/*** 根据系统时间、前缀、后缀产生一个文件*/public static File createFile(File folder, String prefix, String suffix) {if (!folder.exists() || !folder.isDirectory()) folder.mkdirs();SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.CHINA);String filename = prefix + dateFormat.format(new Date(System.currentTimeMillis())) + suffix;return new File(folder, filename);}/*** 打开相册*/public void photoAlbum(Activity activity, int requestCode) {Intent intentToPickPic = new Intent(Intent.ACTION_PICK, null);// 单个图片类型:"image/jpeg 、 image/png等的类型",所有类型:"image/*"intentToPickPic.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");activity.startActivityForResult(intentToPickPic, requestCode);}
}

图片裁剪页面

package com.lib.common.image;import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.net.Uri;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;
import android.widget.RelativeLayout;import com.lib.common.R;
import com.lib.common.constant.Constants;
import com.lib.common.ui.base.BaseActivity;
import com.lib.common.util.BitmapUtil;
import com.lib.common.util.DensityUtil;
import com.lib.common.util.FileUtil;
import com.lib.common.util.LogUtil;import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;public class CorpImgActivity extends BaseActivity implements View.OnTouchListener {private static final String TAG = "CorpImgActivity";private View mCropView;private ImageView mCorpImg;private RelativeLayout mCropLayout;private Bitmap mCropBitmap;private int top, left;private float downX, downY;private final int ZOOM = 1, DRAG = 0;private float oldSpacing = 1f;private int state;/*** 记录缩放时两指中间点坐标*/private PointF mid = new PointF();private boolean isMain, isPointer;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setActivityTitle(getString(R.string.crop_img));setRightTopMenuShow(true);setRightTopTitle(getString(R.string.save));initView();initData();}@Overridepublic int setLayoutId() {return R.layout.activity_corp_img;}private void initView() {mCropView = findViewById(R.id.crop_handler_select);mCorpImg = findViewById(R.id.crop_handler_img);mCropLayout = findViewById(R.id.crop_handler_layout);//添加缩放功能mCorpImg.setOnTouchListener(this);}private void initData() {Bundle bundle = getIntent().getExtras();if (bundle != null && bundle.containsKey(Constants.IMAGE_URI)) {Uri imageUri = (Uri) bundle.get(Constants.IMAGE_URI);if (imageUri != null) {try {// 要裁剪的图片mCropBitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(imageUri));mCorpImg.setImageBitmap(mCropBitmap);} catch (FileNotFoundException e) {e.printStackTrace();}}}if (bundle != null && bundle.containsKey(Constants.IMAGE_PATH)) {String imagePath = (String) bundle.get(Constants.IMAGE_PATH);if (imagePath != null) {try {// 要裁剪的图片mCropBitmap = BitmapFactory.decodeStream(new FileInputStream(imagePath));// 旋转图片int degree = BitmapUtil.getBitmapDegree(imagePath);LogUtil.i(TAG, "degree " + degree);if (degree != 0)mCropBitmap = BitmapUtil.rotateBitmapByDegree(mCropBitmap, degree);mCorpImg.setImageBitmap(mCropBitmap);} catch (FileNotFoundException e) {e.printStackTrace();}}}}@Overridepublic boolean onTouch(View view, MotionEvent motionEvent) {switch (motionEvent.getAction() & motionEvent.getActionMasked()) {case MotionEvent.ACTION_POINTER_DOWN:// 次要点被点击oldSpacing = spacing(motionEvent);if (oldSpacing > 10f) {isPointer = false;isMain = false;state = ZOOM;midPoint(mid, motionEvent);}break;case MotionEvent.ACTION_POINTER_UP:// 次要点松开isPointer = true;if (isPointer && isMain) {isPointer = false;isMain = false;state = DRAG;oldSpacing = 1f;}break;case MotionEvent.ACTION_DOWN:downX = motionEvent.getX();downY = motionEvent.getY();break;case MotionEvent.ACTION_MOVE:Matrix matrix = mCorpImg.getImageMatrix();if (state == DRAG) {// 拖拽matrix.postTranslate(motionEvent.getX() - downX, motionEvent.getY() - downY);downX = motionEvent.getX();downY = motionEvent.getY();} else if (state == ZOOM && !isPointer && !isMain) {// 放大缩小float newSpacing = spacing(motionEvent);float scale = newSpacing / oldSpacing;matrix.postScale(scale, scale, mid.x, mid.y);oldSpacing = newSpacing;}break;case MotionEvent.ACTION_UP:// 用户多点触碰释放时,需要同时释放所有点才初始,防止发生偏移。isMain = true;if (isPointer && isMain) {isPointer = false;isMain = false;state = DRAG;oldSpacing = 1f;}break;}mCorpImg.invalidate();return true;}/*** 多点触控时,计算最先放下的两指距离** @param event* @return*/private float spacing(MotionEvent event) {float x = event.getX(0) - event.getX(1);float y = event.getY(0) - event.getY(1);return (float) Math.sqrt(x * x + y * y);}/*** 多点触控时,计算最先放下的两指中心坐标** @param point* @param event*/private void midPoint(PointF point, MotionEvent event) {float x = event.getX(0) + event.getX(1);float y = event.getY(0) + event.getY(1);point.set(x / 2, y / 2);}@Overridepublic void onWindowFocusChanged(boolean hasFocus) {super.onWindowFocusChanged(hasFocus);if (hasFocus) {int layoutWidth = mCropLayout.getWidth();int layoutHeight = mCropLayout.getHeight();int imgWidth = mCropBitmap.getWidth();int imgHeight = mCropBitmap.getHeight();int selectWidth = mCropView.getWidth();int selectHeight = mCropView.getHeight();float scaleNum; // 缩放比例// 将要裁剪的图片长宽高做对比, 将较小的一方做等比缩放成裁剪框大小if (imgWidth < imgHeight) {scaleNum = (selectWidth * 1.0f) / (imgWidth * 1.0f);imgHeight = (int) (scaleNum * imgHeight);imgWidth = selectWidth;} else {scaleNum = (selectHeight * 1.0f) / (imgHeight * 1.0f);imgWidth = (int) (scaleNum * imgWidth);imgHeight = selectHeight;}Matrix matrix = new Matrix();matrix.postScale(scaleNum, scaleNum);// 平移距离matrix.postTranslate((layoutWidth - imgWidth) / 2, (layoutHeight - imgHeight) / 2);// 设置缩放类型为 矩阵mCorpImg.setScaleType(ImageView.ScaleType.MATRIX);mCorpImg.setImageMatrix(matrix);mCorpImg.setImageBitmap(mCropBitmap);}}@Overridepublic void onRightTopMenuClick() {super.onRightTopMenuClick();Bitmap bitmap = getBitmap();File file = FileUtil.createImageFile();file = BitmapUtil.compressImage(bitmap, file);mCropBitmap.recycle();mCropBitmap = null;Intent intent = new Intent();intent.putExtra(Constants.IMAGE_PATH, file.getPath());setResult(RESULT_OK, intent);finish();}/*** 获取裁剪框内截图** @return*/private Bitmap getBitmap() {// 获取截屏mCropLayout.setDrawingCacheEnabled(true);mCropLayout.buildDrawingCache();// 计算裁剪框的开始位置left = (mCropLayout.getWidth() - mCropView.getWidth()) / 2;top = (mCropLayout.getHeight() - mCropView.getHeight()) / 2;// 裁剪框的边框宽度int borderWidth = DensityUtil.dp2px(getContext(), 2.5f);Bitmap finalBitmap = Bitmap.createBitmap(mCropLayout.getDrawingCache(),left + borderWidth, top + borderWidth, mCropView.getWidth() - 2 * borderWidth,mCropView.getHeight() - 2 * borderWidth);// 释放资源mCropLayout.destroyDrawingCache();return finalBitmap;}
}

裁剪页面布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:background="@android:color/black"android:orientation="vertical"><RelativeLayoutandroid:id="@+id/crop_handler_layout"android:layout_width="match_parent"android:layout_height="match_parent"><ImageViewandroid:id="@+id/crop_handler_img"android:layout_width="match_parent"android:layout_height="match_parent" /><Viewandroid:id="@+id/crop_handler_select"android:layout_width="200dp"android:layout_height="200dp"android:layout_centerInParent="true"android:background="@drawable/bg_crop" /></RelativeLayout>
</LinearLayout>