Android 画图板(画笔、箭头、 直线、 折线、橡皮擦)功能优化

在这里插入图片描述

package com.blink.analysis.view;


import android.graphics.Bitmap;
import android.graphics.Paint;
import android.util.DisplayMetrics;
import android.view.View;
import android.content.Context;
import android.graphics.*;
import android.graphics.Paint.Style;
import android.util.AttributeSet;
import android.view.MotionEvent;

import com.blink.analysis.R;

import java.util.ArrayList;


public class HandWriteView extends View {
    private int mMode = 1;
    private Bitmap mBitmap;
    private Canvas mCanvas;
    private Paint mEraserPaint;
    private Paint mPaint;
    private Path mPath;
    private float mX, mY;
    private static final float TOUCH_TOLERANCE = 4;
    private PointF startPoint = new PointF(0, 0);
    private PointF endPoint = new PointF(0, 0);
    //    箭头线
    private Paint arrowPaint;
    private static final float ARROW_WIDTH = 20;
    private static final float ARROW_HEIGHT = 10;
    //    ArrayList<ArrowBean> arrowList;
    //    直线
    private Paint linePaint;
    ArrayList<ArrowBean> lineList;
    //    折线
    private Paint pathPaint;
    //    private Matrix matrix;
    ArrayList<PointF> pathList;
    //    页面
    private int SCREEN_W;
    private int SCREEN_H;
    public static int Pen = 1;
    public static int Eraser = 2;
    public static int ARROW = 3;
    public static int LINE = 4;
    public static int PATH = 5;

    public HandWriteView(Context context) {
        super(context);
        setFocusable(true);
        setScreenWH();
        initPaint();
    }

    private void setScreenWH() {
        DisplayMetrics dm = new DisplayMetrics();
        dm = this.getResources().getDisplayMetrics();
        int screenWidth = dm.widthPixels;
        int screenHeight = dm.heightPixels;
        SCREEN_W = screenWidth;
        SCREEN_H = screenHeight;
    }


    public void clearDraw() {
        mMode = Eraser;
        mCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
        mCanvas.drawLine(0, 0, 720, 1280, mEraserPaint);
        invalidate();
    }

    //设置绘制模式是“画笔”还是“橡皮擦”
    public void setMode(int mode) {
        this.mMode = mode;
    }

    private void initPaint() {
        //折线
        pathList = new ArrayList<>();
        pathPaint = new Paint();
        pathPaint.setColor(Color.GREEN);
        pathPaint.setStrokeWidth(5);
        pathPaint.setStyle(Paint.Style.STROKE);
        pathPaint.setTextSize(36);

        //直线
        lineList = new ArrayList<>();
        linePaint = new Paint();
        linePaint.setColor(Color.BLUE);
        linePaint.setStrokeWidth(5);
        linePaint.setStyle(Paint.Style.STROKE);
        //箭头
//        arrowList = new ArrayList<>();
        arrowPaint = new Paint();
        arrowPaint.setColor(Color.RED);
        arrowPaint.setStrokeWidth(5);
        arrowPaint.setStyle(Paint.Style.STROKE);
        //画笔
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeCap(Paint.Cap.ROUND);
        mPaint.setStrokeJoin(Paint.Join.ROUND);
        mPaint.setColor(Color.BLACK);
        mPaint.setStrokeWidth(10);
        //橡皮擦
        mEraserPaint = new Paint();
        mEraserPaint.setAlpha(0);
        //这个属性是设置paint为橡皮擦重中之重
        //这是重点
        //下面这句代码是橡皮擦设置的重点
        mEraserPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
        //上面这句代码是橡皮擦设置的重点(重要的事是不是一定要说三遍)
        mEraserPaint.setAntiAlias(true);
        mEraserPaint.setDither(true);
        mEraserPaint.setStyle(Paint.Style.STROKE);
        mEraserPaint.setStrokeJoin(Paint.Join.ROUND);
        mEraserPaint.setStrokeWidth(50);

        mPath = new Path();

        mBitmap = Bitmap.createBitmap(SCREEN_W, SCREEN_H, Bitmap.Config.ARGB_8888);
        mCanvas = new Canvas(mBitmap);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
//        画笔
        if (mBitmap != null) {
            canvas.drawBitmap(mBitmap, 0, 0, mPaint);
        }
//        箭头
        if (mMode == ARROW) {
            PointF start = startPoint;
            PointF end = endPoint;
            canvas.drawLine(start.x, start.y, end.x, end.y, arrowPaint);
            drawArrowHead(canvas, start, end);

            canvas.drawBitmap(mBitmap, 0, 0, arrowPaint);
        }
//        直线
        if (mMode == LINE) {
            PointF start = startPoint;
            PointF end = endPoint;
            canvas.drawLine(start.x, start.y, end.x, end.y, linePaint);

            canvas.drawBitmap(mBitmap, 0, 0, linePaint);
        }
//        折线
        if (mMode == PATH) {
            PointF start = startPoint;
            PointF end = endPoint;
            canvas.drawLine(start.x, start.y, end.x, end.y, pathPaint);
            drawAngle(canvas);
            canvas.drawBitmap(mBitmap, 0, 0, pathPaint);
        }
//        橡皮
        if (mMode == Eraser) {
            System.out.println("x="+mX+"---------y="+mY);
            canvas.drawCircle(mX, mY, 30, new Paint());
        }

    }

    private void drawAngle(Canvas canvas) {
        if (pathList.size() == 2) {
            PointF startP = pathList.get(0);
            PointF centerP = pathList.get(1);
            double angle = angleBetweenThreePoints(startP, centerP, endPoint);
            String format = String.format("%.2f", angle).equals("NaN") ? "0" : String.format("%.2f", angle);
            canvas.drawText(format + "°", centerP.x, centerP.y, pathPaint);
        }
        if (pathList.size() == 3) {
            PointF startP = pathList.get(0);
            PointF centerP = pathList.get(1);
            PointF endP = pathList.get(2);
            double angle = angleBetweenThreePoints(startP, centerP, endP);
            // 绘制角度标签
            mCanvas.drawText(String.format("%.2f", angle) + "°", centerP.x, centerP.y, pathPaint);
            pathList.clear();
        }
    }

    private double angleBetweenThreePoints(PointF a, PointF b, PointF c) {
        double ab = Math.sqrt(Math.pow((a.x - b.x), 2.0) + Math.pow((a.y - b.y), 2.0));
        double ac = Math.sqrt(Math.pow((a.x - c.x), 2.0) + Math.pow((a.y - c.y), 2.0));
        double bc = Math.sqrt(Math.pow((b.x - c.x), 2.0) + Math.pow((b.y - c.y), 2.0));
//      余弦定理  cosB = (AB*AB + BC*BC - AC*AC ) / 2*AB*BC
        double cosValue = (ab * ab + bc * bc - ac * ac) / (2 * bc * ab);
        double angle = Math.acos(cosValue) * (180 / Math.PI);
        return angle;
    }


    //画箭头
    private void drawArrowHead(Canvas canvas, PointF start, PointF end) {
        float angle = (float) Math.atan2(end.y - start.y, end.x - start.x);
        PointF arrowEnd = new PointF((float) (end.x - ARROW_WIDTH * Math.cos(angle)), (float) (end.y - ARROW_WIDTH * Math.sin(angle)));
        PointF arrowLeft = new PointF((float) (arrowEnd.x + ARROW_HEIGHT * Math.sin(angle)), (float) (arrowEnd.y - ARROW_HEIGHT * Math.cos(angle)));
        PointF arrowRight = new PointF((float) (arrowEnd.x - ARROW_HEIGHT * Math.sin(angle)), (float) (arrowEnd.y + ARROW_HEIGHT * Math.cos(angle)));
        Path path = new Path();
        path.moveTo(end.x, end.y);
        path.lineTo(arrowLeft.x, arrowLeft.y);
        path.lineTo(arrowRight.x, arrowRight.y);
        path.close();
        canvas.drawPath(path, arrowPaint);
    }

    private void touch_start(float x, float y) {
        mPath.reset();
        mPath.moveTo(x, y);
        mX = x;
        mY = y;
        //如果是“画笔”模式就用mPaint画笔进行绘制
        if (mMode == Pen) {
            mCanvas.drawPath(mPath, mPaint);
        }
        //如果是“橡皮擦”模式就用mEraserPaint画笔进行绘制
        if (mMode == Eraser) {
            mCanvas.drawPath(mPath, mEraserPaint);
        }
        if (mMode == ARROW || mMode == LINE) {
            startPoint = new PointF(x, y);
            endPoint = new PointF(x, y);
        }
        if (mMode == PATH) {
            startPoint = new PointF(x, y);
            endPoint = new PointF(x, y);
            if (pathList.isEmpty()) {
                pathList.add(startPoint);
            } else {
                startPoint = pathList.get(pathList.size() - 1);
            }
        }

    }

    private void touch_move(float x, float y) {
        float dx = Math.abs(x - mX);
        float dy = Math.abs(y - mY);
        if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
            mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
            mX = x;
            mY = y;
            if (mMode == Pen) {
                mCanvas.drawPath(mPath, mPaint);
            }
            if (mMode == Eraser) {
                mCanvas.drawPath(mPath, mEraserPaint);
            }
            if (mMode == ARROW || mMode == LINE) {
                endPoint = new PointF(x, y);
            }
            if (mMode == PATH) {
                endPoint = new PointF(x, y);
            }
        }
    }


    private void touch_up(float x, float y) {
        mPath.lineTo(x, y);
        if (mMode == Pen) {
            mCanvas.drawPath(mPath, mPaint);
        }
        if (mMode == Eraser) {
            mCanvas.drawPath(mPath, mEraserPaint);
            mX = -30;
            mY = -30;
        }
        if (mMode == ARROW) {
            endPoint = new PointF(x, y);
            mCanvas.drawLine(startPoint.x, startPoint.y, endPoint.x, endPoint.y, arrowPaint);
            drawArrowHead(mCanvas, startPoint, endPoint);
        }
        if (mMode == LINE) {
            endPoint = new PointF(x, y);
            mCanvas.drawLine(startPoint.x, startPoint.y, endPoint.x, endPoint.y, linePaint);
        }
        if (mMode == PATH) {
            endPoint = new PointF(x, y);
            pathList.add(endPoint);
            mCanvas.drawLine(startPoint.x, startPoint.y, endPoint.x, endPoint.y, pathPaint);
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        float x = event.getX();
        float y = event.getY();

        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                touch_start(x, y);
                invalidate();
                break;
            case MotionEvent.ACTION_MOVE:
                touch_move(x, y);
                invalidate();
                break;
            case MotionEvent.ACTION_UP:
                touch_up(x, y);
                invalidate();
                break;
        }
        return true;
    }

    class ArrowBean {
        public PointF startPoint;
        public PointF endPoint;

        public ArrowBean(PointF startPoint, PointF endPoint) {
            this.startPoint = startPoint;
            this.endPoint = endPoint;
        }
    }
}
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

魑魅魍魉9527

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值