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

本文介绍了一种基于自定义SurfaceView实现的截图功能,支持多区域选择与撤销操作,适用于Android应用中的灵活截图需求。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

仿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<DrawPath> 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;
    }

    /**
     * 判断四个顶点的位置,绘制矩形
     * @param x
     * @param y
     * @param left
     * @param top
     * @param right
     * @param bottom
     * @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<Postion> position = new ArrayList<>();

    public List<Postion> getPosition() {
        return position;
    }

    public void setPosition(List<Postion> 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 class DrawPath {

        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 class Postion{
        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();
        }
    });
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值