仿PC端QQ截圖,可任意截圖,這里只做了矩形這一種形狀,可同時(shí)支持截取多個(gè)區(qū)域,支持撤銷上次截圖,重新截取。

實(shí)現(xiàn)原理:
自定義SurfaceView,在SurfaceView上繪制具有一個(gè)可拉伸,移動(dòng)的矩形框,當(dāng)點(diǎn)擊截圖按鈕后,計(jì)算矩形框的坐標(biāo)值及原圖尺寸,通過比例將矩形框的坐標(biāo)值轉(zhuǎn)化到原圖中相對(duì)應(yīng)的坐標(biāo),然后進(jìn)行裁剪。
項(xiàng)目源碼:https://github.com/LeeVanie/CavansRect
實(shí)現(xiàn)代碼:
public class CustomSurfaceView extends SurfaceView implements SurfaceHolder.Callback, Runnable, Handler.Callback {?
?// SurfaceHolder private SurfaceHolder mSurfaceHolder;
? ? /**
? ? * 屏幕尺寸
? ? */? ??
private int viewWidth;
? ? private int viewHeight;
? ? // 線寬? ??
private int StrokeWidth = 5;
? ? private boolean startDraw;
? ? //半徑? ??
private int radius;
? ? // Path? ??
private Path mPath = new Path();
? ? // 畫筆? ??
private Paint mpaint = new Paint();
? ? private Canvas canvas;
? ? //滑板背景(保存繪制的圖片)? ??
private Bitmap saveBitmap;
? ? //圖像? ??
Bitmap bitmap;
? ? // 圖片路徑? ??
private String urlPath;
? ? private List drawPathList = new ArrayList<>();
? ? /**
? ? * X 、 Y 方向的圖片和屏幕比例
? ? */? ? private float scaleX, scaleY;
? ? /**
? ? * 0矩形
? ? * 1撤回
? ? */? ??
private static int state = 0;
? ? public void setState(int state) {
? ? ? ? this.state = state;
? ? }
? ? public CustomSurfaceView(Context context, String url, boolean s) {
? ? ? ? this(context, null);
? ? ? ? this.urlPath = url;
? ? ? ? saveBitmap = Bitmap.createBitmap(720, 1000, Bitmap.Config.ARGB_8888);
? ? }
? ? public CustomSurfaceView(Context context, AttributeSet attrs) {
? ? ? ? this(context, attrs, 0);
? ? }
? ? public CustomSurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {
? ? ? ? super(context, attrs, defStyleAttr);
? ? ? ? initView(); // 初始化? ?
?}
? ? private void initView() {
? ? ? ? setMeasuredDimension(720, 1000);
? ? ? ? mSurfaceHolder = getHolder();
? ? ? ? mSurfaceHolder.addCallback(this);
? ? ? ? mSurfaceHolder.setFormat(PixelFormat.TRANSPARENT);
? ? ? ? setFocusable(true);
? ? ? ? setFocusableInTouchMode(true);
? ? ? ? this.setKeepScreenOn(true);
? ? }
? ? private Handler handler = new Handler(this);
? ? @Override? ? public void run() {
? ? ? ? while (startDraw) {
? ? ? ? ? ? if (urlPath != null) {
? ? ? ? ? ? ? ? ? ? try {
? ? ? ? ? ? ? ? ? ? ? ? bitmap = BitmapUtils.toBitmap(urlPath, getWidth(), getHeight());
? ? ? ? ? ? ? ? ? ? ? ? if (bitmap == null) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? startDraw = true;
? ? ? ? ? ? ? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? ? ? ? ? ? ? startDraw = false;
? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? } catch (Exception e) {
? ? ? ? ? ? ? ? ? ? ? ? Log.d("CustomSurfaceView", "CustomSurfaceView ------- " + e.toString());
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }
? ? ? ? ? ? handler.sendEmptyMessage(1);
? ? ? ? }
? ? }
? ? /*
? ? ? ? * 創(chuàng)建
? ? ? ? */? ?
?@Override? ??
public void surfaceCreated(SurfaceHolder holder) {
? ? ? ? startDraw = true;
? ? ? ? canvas = mSurfaceHolder.lockCanvas();
? ? ? ? canvas.setBitmap(saveBitmap);
? ? ? ? mSurfaceHolder.unlockCanvasAndPost(canvas);
? ? ? ? new Thread(this).start();
? ? }
? ? @Override? ??
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
? ? ? ? super.onMeasure(widthMeasureSpec, heightMeasureSpec);
? ? ? ? viewWidth = getWidth();
? ? ? ? viewHeight = getHeight();
? ? }
? ? @Override? ??
public void surfaceChanged(SurfaceHolder holder, int format, int width,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? int height) {
? ? }
? ? /*
? ? * 銷毀
? ? */? ??
@Override? ??
public void surfaceDestroyed(SurfaceHolder holder) {
? ? ? ? startDraw = false;
? ? }
? ? int startX;
? ? int startY;
? ? int stopX;
? ? int stopY;
? ? @Override? ??
public boolean onTouchEvent(MotionEvent event) {
? ? ? ? switch (event.getAction()) {
? ? ? ? ? ? case MotionEvent.ACTION_DOWN:
? ? ? ? ? ? ? ? mPath = new Path();
? ? ? ? ? ? ? ? mpaint = new Paint();
? ? ? ? ? ? ? ? startX = 0;
? ? ? ? ? ? ? ? startY = 0;
? ? ? ? ? ? ? ? startX = (int) event.getX();
? ? ? ? ? ? ? ? startY = (int) event.getY();
? ? ? ? ? ? ? ? mPath.moveTo(startX, startY);
? ? ? ? ? ? ? ? break;
? ? ? ? ? ? case MotionEvent.ACTION_MOVE:
? ? ? ? ? ? ? ? stopX = (int) event.getX();
? ? ? ? ? ? ? ? stopY = (int) event.getY();
? ? ? ? ? ? ? ? if (state == 0) {
? ? ? ? ? ? ? ? ? ? draws();
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? break;
? ? ? ? ? ? case MotionEvent.ACTION_UP:
? ? ? ? ? ? ? ? if (drawPathList.size() + 1 <= 1){
? ? ? ? ? ? ? ? ? ? if (state == 0) {
? ? ? ? ? ? ? ? ? ? ? ? mPath.moveTo(startX, startY);
? ? ? ? ? ? ? ? ? ? ? ? mPath.lineTo(startX, stopY);
? ? ? ? ? ? ? ? ? ? ? ? mPath.lineTo(stopX, stopY);
? ? ? ? ? ? ? ? ? ? ? ? mPath.lineTo(stopX, startY);
? ? ? ? ? ? ? ? ? ? ? ? mPath.lineTo(startX, startY);
? ? ? ? ? ? ? ? ? ? ? ? mPath.close();
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? position.add(union((int) (stopX / scaleX), (int) (stopY / scaleY),
? ? ? ? ? ? ? ? ? ? ? ? (int) (startX / scaleX), (int) (startY / scaleY),
? ? ? ? ? ? ? ? ? ? ? ? (int) (startX / scaleX), (int) (startY / scaleY)));
? ? ? ? ? ? ? ? setPosition(position);
? ? ? ? ? ? ? ? drawPathList.add(new DrawPath(mpaint, mPath));
? ? ? ? ? ? ? ? //? 限制繪制矩形個(gè)數(shù)? ? ? ? ? ? ? ?
?if (drawPathList.size() == 3){?
? ? ? ? ? ? ? ? ? ? drawPathList.remove(drawPathList.size() - 2);
//? ? ? ? ? ? ? ? ? ? drawPathList.add(new DrawPath(mpaint, mPath));? ? ? ? ? ? ? ?
?}
? ? ? ? ? ? ? ? if (position.size() == 3){
? ? ? ? ? ? ? ? ? ? position.remove(position.size() - 2);
//? ? ? ? ? ? ? ? ? ? position.add(union((int) (stopX / scaleX), (int) (stopY / scaleY),
//? ? ? ? ? ? ? ? ? ? ? ? ? ? (int) (startX / scaleX), (int) (startY / scaleY),
//? ? ? ? ? ? ? ? ? ? ? ? ? ? (int) (startX / scaleX), (int) (startY / scaleY)));? ? ? ? ? ? ? ? ? ??
setPosition(position);
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? break;
? ? ? ? }
? ? ? ? return true;
? ? }
? ? /**? ? * 判斷四個(gè)頂點(diǎn)的位置,繪制矩形? ?
?* @paramx? ??
?* @paramy? ?
?* @paramleft? ?
?* @paramtop? ?
?* @paramright? ?
?* @parambottom? ??
?* @return
*/? ??
public Postion union(int x, int y, int left, int top, int right, int bottom) {
? ? ? ? int temp = 0;
? ? ? ? if (x < left) {
? ? ? ? ? ? temp = left;
? ? ? ? ? ? left = x;
? ? ? ? ? ? right = temp;
? ? ? ? } else if (x > right) {
? ? ? ? ? ? temp = right;
? ? ? ? ? ? right = x;
? ? ? ? ? ? left = temp;
? ? ? ? }
? ? ? ? if (y < top) {
? ? ? ? ? ? temp = top;
? ? ? ? ? ? top = y;
? ? ? ? ? ? bottom = temp;
? ? ? ? } else if (y > bottom) {
? ? ? ? ? ? temp = bottom;
? ? ? ? ? ? bottom = y;
? ? ? ? ? ? top = temp;
? ? ? ? }
? ? ? ? return new Postion(left, top, right, bottom);
? ? }
? ? /**
? ? * 獲取繪制的四個(gè)點(diǎn)在原圖的位置集合
? ? */? ?
?private List position = new ArrayList<>();
? ? public List getPosition() {
? ? ? ? return position;
? ? }
? ? public void setPosition(List position1) {
? ? ? ? this.position = position1;
? ? }
? ? public void draws() {
? ? ? ? if (bitmap == null) {
? ? ? ? ? ? Toast.makeText(getContext(), "加載圖片失敗", Toast.LENGTH_SHORT).show();
? ? ? ? ? ? Log.e("msg", "加載圖片失敗");
? ? ? ? ? ? return;
? ? ? ? }
? ? ? ? canvas = mSurfaceHolder.lockCanvas();
? ? ? ? Rect rectF = new Rect(0, 0, getWidth(), getHeight());? //w和h分別是屏幕的寬和高,也就是你想讓圖片顯示的寬和高? ? ? ??
scaleX = (float) getWidth() / bitmap.getWidth();
? ? ? ? scaleY = (float) getHeight() / bitmap.getHeight();
? ? ? ? canvas.drawBitmap(bitmap, null, rectF, null);
? ? ? ? mpaint.setStyle(Paint.Style.STROKE);
? ? ? ? mpaint.setAntiAlias(true);
? ? ? ? for (int i = 0; i < drawPathList.size(); i++) {
? ? ? ? ? ? //把path中的路線繪制出來? ? ? ? ? ?
?canvas.drawPath(drawPathList.get(i).path, drawPathList.get(i).paint);
? ? ? ? }
? ? ? ? mpaint.setColor(Color.RED);
? ? ? ? if (state == 0) {
? ? ? ? ? ? mpaint.setColor(Color.RED);
? ? ? ? ? ? mpaint.setStyle(Paint.Style.STROKE);
? ? ? ? ? ? mpaint.setStrokeWidth(StrokeWidth);
? ? ? ? ? ? canvas.drawRect(startX, startY, stopX, stopY, mpaint);
? ? ? ? }
? ? ? ? mSurfaceHolder.unlockCanvasAndPost(canvas);
? ? }
? ? @Override? ??
public boolean handleMessage(Message msg) {
? ? ? ? canvas = mSurfaceHolder.lockCanvas();
? ? ? ? //這里相當(dāng)于是一個(gè)預(yù)覽圖? ? ? ??
Rect rectF = new Rect(0, 0, viewWidth, viewHeight);??
//w和h分別是屏幕的寬和高,也就是你想讓圖片顯示的寬和高? ? ? ?
?if (bitmap!= null&& canvas!= null)
? ? ? ? canvas.drawBitmap(bitmap, null, rectF, null);
? ? ? ? if (canvas!= null)
? ? ? ? mSurfaceHolder.unlockCanvasAndPost(canvas);
? ? ? ? if (bitmap != null) {
? ? ? ? ? ? startDraw = false;
? ? ? ? }
? ? ? ? return false;
? ? }
? ? public classDrawPath{? ? ? ??
public Paint paint;
? ? ? ? public Path path;
? ? ? ? public DrawPath(Paint paint, Path path) {
? ? ? ? ? ? this.paint = paint;
? ? ? ? ? ? this.path = path;
? ? ? ? }
? ? }
? ? /**
? ? * 撤銷上一個(gè)矩形
? ? */? ??
public void revocation() {
? ? ? ? if (drawPathList.size() > 0) {
? ? ? ? ? ? drawPathList.remove(drawPathList.size() - 1);
? ? ? ? ? ? position.remove(position.size() - 1);
? ? ? ? ? ? if (drawPathList.size() == 0){
? ? ? ? ? ? ? ? position = new ArrayList<>();
? ? ? ? ? ? }
? ? ? ? ? ? startX = 0; startY = 0; stopX = 0; stopY = 0;
? ? ? ? ? ? draws();
? ? ? ? }
? ? }
? ? /**
? ? * 位置 Bean
? ? */? ??
public classPostion{? ? ? ??
public int left;
? ? ? ? public int top;
? ? ? ? public int right;
? ? ? ? public int bottom;
? ? ? ? public int getLeft() {
? ? ? ? ? ? return left;
? ? ? ? }
? ? ? ? public int getTop() {
? ? ? ? ? ? return top;
? ? ? ? }
? ? ? ? public int getRight() {
? ? ? ? ? ? return right;
? ? ? ? }
? ? ? ? public int getBottom() {
? ? ? ? ? ? return bottom;
? ? ? ? }
? ? ? ? public Postion(int left, int top, int right, int bottom) {
? ? ? ? ? ? this.left = left;
? ? ? ? ? ? this.top = top;
? ? ? ? ? ? this.right = right;
? ? ? ? ? ? this.bottom = bottom;
? ? ? ? }
? ? }
}
在Activity中對(duì)CustomSurfaceView進(jìn)行實(shí)例化,并傳入圖片,監(jiān)聽按鈕進(jìn)行裁剪和撤銷處理
surfce = new CustomSurfaceView(CropActivity.this, photoPath, false);?
?linear.addView(surfce); //設(shè)置當(dāng)前狀態(tài)為畫矩形
? ? surfce.setState(0);? ??
findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
? ? ? ? @Override
? ? ? ? public void onClick(View v) {
? ? ? ? ? ? position = new ArrayList<>();? ? ? ? ? ?
?if (bitmap != null) {
? ? ? ? ? ? ? ? position = surfce.getPosition();? ? ? ? ? ? ??
? bitmap1 = null;? ? ? ? ? ? ??
? bitmap2 = null;? ? ? ? ??
? ? ? bitmap1 = Bitmap.createBitmap(bitmap, surfce.getPosition().get(0).getLeft(),
? ? ? ? ? ? ? ? ? ? ? ? surfce.getPosition().get(0).getTop(),
? ? ? ? ? ? ? ? ? ? ? ? surfce.getPosition().get(0).getRight() - surfce.getPosition().get(0).getLeft(),
? ? ? ? ? ? ? ? ? ? ? ? surfce.getPosition().get(0).getBottom() - surfce.getPosition().get(0).getTop());? ? ? ? ? ? ? ?
?bitmap2 = Bitmap.createBitmap(bitmap, surfce.getPosition().get(1).getLeft(),
? ? ? ? ? ? ? ? ? ? ? ? surfce.getPosition().get(1).getTop(),
? ? ? ? ? ? ? ? ? ? ? ? surfce.getPosition().get(1).getRight() - surfce.getPosition().get(1).getLeft(),
? ? ? ? ? ? ? ? ? ? ? ? surfce.getPosition().get(1).getBottom() - surfce.getPosition().get(1).getTop());? ? ? ? ? ??
? ? if (bitmap == null || bitmap1 == null || bitmap2 == null || position.size() != 2) {
? ? ? ? ? ? ? ? ? ? final AlertDialog.Builder builder = new AlertDialog.Builder(CropActivity.this);? ? ? ? ? ? ? ? ? ? builder.setMessage("照片裁剪失敗,請(qǐng)重新裁剪!!")
? ? ? ? ? ? ? ? ? ? ? ? ? ? .setTitle("提示")
? ? ? ? ? ? ? ? ? ? ? ? ? ? .setPositiveButton("返回", null);? ? ? ? ? ? ?
?? } else {
? ? ? ? ? ? ? ? ? ? image01.setImageBitmap(bitmap1);? ? ? ? ? ? ? ??
? ? image02.setImageBitmap(bitmap2);? ? ? ? ??
? ? ? }
? ? ? ? ? ? }
? ? ? ? }
? ? });? ?
?findViewById(R.id.canle).setOnClickListener(new View.OnClickListener() {
? ? ? ? @Override
? ? ? ? public void onClick(View v) {
? ? ? ? ? ? surfce.revocation(); ? ?//撤銷
? ? }
? ? });