Android 仿PC端QQ自由截图,可支持一次截多个区域

仿PC端QQ截图,可任意截图,这里只做了矩形这一种形状,可同时支持截取多个区域,支持撤销上次截图,重新截取。

实现原理:

自定义SurfaceView,在SurfaceView上绘制具有一个可拉伸,移动的矩形框,当点击截图按钮后,计算矩形框的坐标值及原图尺寸,通过比例将矩形框的坐标值转化到原图中相对应的坐标,然后进行裁剪。

项目源码:https://github.com/LeeVanie/CavansRect

实现代码:

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);

        }

    }

    /*

        * 创建

        */   

 @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));

                //  限制绘制矩形个数               

 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;

    }

    /**    * 判断四个顶点的位置,绘制矩形   

 * @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);

    }

    /**

    * 获取绘制的四个点在原图的位置集合

    */   

 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();

        //这里相当于是一个预览图        

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;

        }

    }

    /**

    * 撤销上一个矩形

    */    

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中对CustomSurfaceView进行实例化,并传入图片,监听按钮进行裁剪和撤销处理

surfce = new CustomSurfaceView(CropActivity.this, photoPath, false); 

 linear.addView(surfce); //设置当前状态为画矩形

    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("照片裁剪失败,请重新裁剪!!")

                            .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();    //撤销

    }

    });

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 195,783评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,360评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 142,942评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,507评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,324评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,299评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,685评论 3 386
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,358评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,652评论 1 293
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,704评论 2 312
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,465评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,318评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,711评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,991评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,265评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,661评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,864评论 2 335

推荐阅读更多精彩内容