美文网首页
Android 编辑图片 Canvas画图,涂鸦,马赛克等(二)

Android 编辑图片 Canvas画图,涂鸦,马赛克等(二)

作者: BigP | 来源:发表于2019-02-27 16:25 被阅读0次

    需求功能详解

    单纯的编辑图片的功能,能够在界面上进行图形的绘制,线条的涂鸦,和画马赛克的绘制,并且有撤销的功能。

    画图形

    继续上一篇的内容,涂鸦已经完成,接下来我们一起来完成画图形的操作:这里看到我暂时提供了四种图形的绘制:

    图形种类
    可以看到有矩形椭圆圆形箭头四种图形,除了箭头,其他三种图形都很简单。

    实现思路

    这里先说除了箭头的三种图形的绘制吧。要想绘制一个图形,只需要明白两个知识点就行了:

    • 需要绘制什么图形
    • 按下的点和终点,两个点就能确定一个四边框框,我们所要绘制的图形,其实就由这个四边框确定位置和大小

    下面已绘制矩形为例
    首先设置基础画笔:

    if (mode == MODE.GRAPH_MODE) {
            mTempPaint = new Paint();
            mTempPaint.setAntiAlias(true);
            mTempPaint.setColor(mPaintColor);
            mTempPaint.setStrokeWidth(mPaintWidth);
            mTempPaint.setStrokeCap(Paint.Cap.ROUND);
            mTempPaint.setStrokeJoin(Paint.Join.ROUND);
    }
    

    创建保存图形绘制的队列,同样是为了更好的管理绘制和撤销操作:

    private ArrayList<DrawGraphBean> mGraphPath = new ArrayList<>();
    

    这里存储的实例与之前涂鸦功能的略有不同,需要记录按下时的坐标,和不断移动的结束坐标,以及所画图形的种类:

    class DrawGraphBean {
        public float startX, startY, endX, endY;
        public GRAPH_TYPE type;
        public Paint paint;
    
        DrawGraphBean(float startX, float startY, float endx, float endY, GRAPH_TYPE type, Paint paint) {
            this.startX = startX;
            this.startY = startY;
            this.endX = endx;
            this.endY = endY;
            this.type = type;
            this.paint = paint;
        }
    }
    

    给图形种类给出枚举(不进行设置,默认是矩形):

    public enum GRAPH_TYPE {
        RECT, CIRCLE, OVAL, ARROW
    }
    

    明白了原理和思路,真正画起来,就简单多了,同样在Action_Down中记下起始点,画笔,然后添加到队列中:

    if (mMode == MODE.GRAPH_MODE) {
        mStartX = event.getX();
        mStartY = event.getY();
        setModePaint(mMode);
    
        // 添加到队列中
        DrawGraphBean graphBean = new DrawGraphBean(mStartX, mStartY, mStartX, mStartY, mCurrentGraphType, mTempPaint);
    
        mPaths.add(mMode);
        mGraphPath.add(graphBean);
    }
    

    然后在Action_Move中,取出队列的最后一条数据,将他的终点坐标进行更新,那么在onDraw()绘制时,就能画出不断跟随手指改变的图形了:

    if (mMode == MODE.GRAPH_MODE && mGraphPath.size() > 0) {
        DrawGraphBean tempBean = mGraphPath.get(mGraphPath.size() - 1);
        tempBean.endX = mMoveX;
        tempBean.endY = mMoveY;
    }
    

    Action_Up中只需要将新建的画笔置空即可:

    mTempPaint = null;
    

    最后,在onDraw()中,将队列中的图形一一绘制出来即可:

    /**
     * 画图形
    */
    private void drawGraphs(Canvas canvas) {
        if (mGraphPath.size() > 0) {
            for (DrawGraphBean graphBean : mGraphPath) {
                if (graphBean.type == GRAPH_TYPE.RECT) {
                    graphBean.paint.setStyle(Paint.Style.STROKE);
                    canvas.drawRect(graphBean.startX, graphBean.startY, graphBean.endX, graphBean.endY, graphBean.paint);
                } else if (graphBean.type == GRAPH_TYPE.OVAL) {
                    graphBean.paint.setStyle(Paint.Style.STROKE);
                    canvas.drawOval(new RectF(graphBean.startX, graphBean.startY, graphBean.endX, graphBean.endY), graphBean.paint);
                } else if (graphBean.type == GRAPH_TYPE.CIRCLE) {
                    graphBean.paint.setStyle(Paint.Style.STROKE);
                    // 计算半径
                    float radius = Math.min(Math.abs(graphBean.startX - graphBean.endX), Math.abs(graphBean.startY - graphBean.endY)) / 2;
                    float centerX, centerY;
                    centerX = graphBean.endX >= graphBean.startX ? graphBean.startX + radius : graphBean.startX - radius;
                    centerY = graphBean.endY >= graphBean.startY ? graphBean.startY + radius : graphBean.startY - radius;
                    canvas.drawCircle(centerX, centerY, radius, graphBean.paint);
                } else if (graphBean.type == GRAPH_TYPE.ARROW) {
                    graphBean.paint.setStyle(Paint.Style.FILL);
                    drawArrow(graphBean.startX, graphBean.startY, graphBean.endX, graphBean.endY, canvas, graphBean.paint);
                }
            }
        }
    }
    

    代码粗解:onDraw()中画图形的部分可以看出,根据图形的种类,分别进行了对应的绘制操作:除了箭头的图形,Canvas都已经给我们提供了系统方法,分别是drawRect,drawOvaldrawCircle,只有画圆形,需要简单的计算,其他都是一句话搞定~


    • 最后再讲解一下箭头的绘制
      画箭头的方法,其实类似于系统提供的画Rect等操作,其实就是把Path连接起来,绘制成的特殊的图形:
    /**
     * 画箭头
    */
    private void drawArrow(float sx, float sy, float ex, float ey, Canvas canvas, Paint paint) {
        int size = 8;
        int count = 30;
        float x = ex - sx;
        float y = ey - sy;
        double d = x * x + y * y;
        double r = Math.sqrt(d);
        float zx = (float) (ex - (count * x / r));
        float zy = (float) (ey - (count * y / r));
        float xz = zx - sx;
        float yz = zy - sy;
        double zd = xz * xz + yz * yz;
        double zr = Math.sqrt(zd);
        Path triangle = new Path();
        triangle.moveTo(sx, sy);
        triangle.lineTo((float) (zx + size * yz / zr), (float) (zy - size * xz / zr));
        triangle.lineTo((float) (zx + size * 2 * yz / zr), (float) (zy - size * 2 * xz / zr));
        triangle.lineTo(ex, ey);
        triangle.lineTo((float) (zx - size * 2 * yz / zr), (float) (zy + size * 2 * xz / zr));
        triangle.lineTo((float) (zx - size * yz / zr), (float) (zy + size * xz / zr));
        triangle.close();
        canvas.drawPath(triangle, paint);
    }
    

    只需要给出起点和终点坐标,还有一点需要注意的是,箭头的画笔需要设置成实心的,那么箭头就绘制完成了~

    相关文章

    Android 编辑图片 Canvas画图,涂鸦,马赛克等(一)
    Android 编辑图片 Canvas画图,涂鸦,马赛克等(三)

    相关文章

      网友评论

          本文标题:Android 编辑图片 Canvas画图,涂鸦,马赛克等(二)

          本文链接:https://www.haomeiwen.com/subject/tjhfuqtx.html