Android 绘图——Canvas

629 阅读5分钟

Canvas简介

Canvas也就是Android中的画布,它保存了一些列的draw方法,你可以是用Canvas绘制图形、文字和位图等,其功能可谓是十分的强大,几乎可以绘制所有的图像和文字。既然Canvas功能如此强大,其丰富了Android的图形,也是Android图形学不可或缺的类,而学习和熟练Canvas,可谓是学习Android UI的重点之一,接下来我们开始学习Canvas的API。

Canvas绘图

既然Canvas提供了绘制图形的功能,那么看下其对应的API有那些。

绘制直线
public class CanvasView extends View {
    Paint paint;
    public CanvasView(Context context) {
        this(context,null);
    }

    public CanvasView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        paint = new Paint();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        paint.setColor(Color.RED);
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth(5);
        canvas.drawLine(0, 0, 100, 100, paint);
    }
}

使用数组,绘制直线

float []pts = {0,0,100,100,200,200,300,300};
canvas.drawLines(pts, paint);

先绘制(0,0)到(100,100)的直线,然后绘制(200,200)到(300,300)的直线。

效果图.png

定义数组,也可以使用下面语句来绘制直线

drawLines(@Size(multiple = 4) @NonNull float[] pts, int offset, int count, @NonNull Paint paint)

pts:坐标数组 offset:设置线的间隔距离 count:绘制直线的条数 paint:画笔

drawPoint

绘制点:

drawPoint(float x, float y, @NonNull Paint paint)

绘制多个点:

float []pts = {0,0,100,100,200,200,300,300};
canvas.drawPoints(pts, paint);

效果图.png

drawRect

绘制矩形,矩形区域有两种表示方式:Rect和RectF,Rect表示int类型,RectF表示float类型。

RectF r = new RectF(100, 100, 400, 500);
canvas.drawRect(r, paint);

效果图.png

也可以如下表示:

drawRect(float left, float top, float right, float bottom, @NonNull Paint paint)
drawRoundRect

使用drawRoundRect,绘制圆角矩形

drawRoundRect(@NonNull RectF rect, float rx, float ry, @NonNull Paint paint)

rx:x轴的圆角半径大小 ry:y轴的圆角半径大小

RectF r = new RectF(100, 100, 400, 500);
canvas.drawRoundRect(r, 100, 100, paint);

效果图.png

drawCircle

绘制圆 :

drawCircle(float cx, float cy, float radius, @NonNull Paint paint)

cx、cy:圆心坐标 radius:半径

canvas.drawCircle(300, 300, 200, paint);

效果图.png

drawOval

使用drawOval函数绘制椭圆

drawOval(@NonNull RectF oval, @NonNull Paint paint) oval:定义的矩形 paint:画笔

除了上述方法参数,可以使用以下方法参数:

drawOval(float left, float top, float right, float bottom, @NonNull Paint paint)

之所以提供一个矩形区域,是因为该椭圆是矩形的内切圆。

RectF r = new RectF(100, 100, 400, 500);
canvas.drawRect(r, paint);
canvas.drawOval(r, paint);

效果图.png

drawArc

使用drawArc方法绘制扇形图。

drawArc(@NonNull RectF oval, float startAngle, float sweepAngle, boolean useCenter,@NonNull Paint paint)

oval:矩形,该扇形是在矩形区域内绘制的,而且围绕着矩形的中心点来绘制。 startAngle:开始角度,相对X轴正方向 sweepAngle:画多少角度的弧度 useCenter:false表示只有一个纯弧线,true表示闭合的边 paint:画笔

RectF r = new RectF(100, 100, 400, 500);
canvas.drawRect(r, paint);
canvas.drawArc(r, 0, 90, true, paint);//顺时针旋转90度

效果图.png

drawPath

使用drawPath来绘制路径,更加灵活的绘制出各式各样的图形。绘制路径,我们需要理解以下几个方法: 1)moveTo(float x, float y):画笔落笔的位置 2)lineTo(float x, float y):画笔移动的到(x,y)坐标,并沿着绘制出路径。 3)cubicTo(float x1, float y1, float x2, float y2,float x3, float y3):实现贝塞尔曲线路径, (x1,y1) 为控制点,(x2,y2)为控制点,(x3,y3) 为结束点。 4)quadTo(float x1, float y1, float x2, float y2):也是绘制贝塞尔曲线,即椭圆曲线。(x1,y1)控制点,(x2,y2)结束点。 5)arcTo:绘制弧线。

Path path = new Path();
path.moveTo(100, 100);
path.lineTo(200, 100);
path.cubicTo(250, 200, 350, 300, 450, 400);
path.close();
canvas.drawPath(path, paint);

效果图.png

弧线
RectF r = new RectF(100, 100, 400, 500);
Path path = new Path();
path.addArc(r, 30, 70);
canvas.drawPath(path, paint);
圆角矩形路径
RectF r = new RectF(100, 100, 400, 500);
Path path = new Path();
float radii[] = {//左上角开始,顺时针依次的角度
                         10,//x1
                         10,//y1
                         10,//x2
                         10,//y2
                         10,//x3
                         10,//y30
                         50,//x4
                         60};//y4
path.addRoundRect(r, radii, Path.Direction.CCW);
canvas.drawPath(path, paint);

效果图.png

Canvas变换技巧

Canvas变换包括: 1)平移(Translate) 2)缩放(Scale) 3)旋转(Rotate) 4)斜拉画布(Skew) 5)裁剪画布(clip)

平移
RectF r = new RectF(0, 0, 400, 500);
canvas.drawRect(r, paint);
paint.setColor(Color.BLUE);
//将画布平移
canvas.translate(50, 50);
canvas.drawRect(r, paint);

效果图.png

上图中画布平移了,蓝色的矩形平移了,但是红色的矩形没有平移,是因为当canvas执行drawXXX的时候就会新建一个新的画布图层,而平移知识平移新的图层。

RectF r = new RectF(0, 0, 400, 500);
canvas.drawRect(r, paint);
paint.setColor(Color.BLUE);
 //将画布平移
canvas.translate(50, 50);
canvas.drawRect(r, paint);
RectF r2 = new RectF(0, 0, 400, 500);
paint.setColor(Color.GREEN);
canvas.drawRect(r2, paint);

效果图.png

从上图中可以看到绿色矩形覆盖了蓝色的矩形,虽然draw的时候,新建了一个画布图层,但是还是会沿用之前设置的平移变换。不可逆的。解决这种情况需要使用save和restore来解决。

缩放

scale(float sx, float sy)

sx、sy:分别对x/y方向的一个缩放系数,画布的缩放会导致里面所有的绘制的东西都会有一个缩放效果。

RectF r = new RectF(0, 0, 400, 500);
canvas.drawRect(r, paint);
paint.setColor(Color.BLUE);
canvas.scale(1.5f, 0.5f);
canvas.drawRect(r, paint);

效果图.png

旋转

rotate(float degrees),degrees:旋转角度,顺时针旋转 rotate(float degrees, float px, float py),degrees旋转角度,(px,py)旋转中心点坐标

RectF r = new RectF(200, 200, 400, 500);
canvas.drawRect(r, paint);
paint.setColor(Color.BLUE);
canvas.rotate(45);
canvas.drawRect(r, paint);
斜拉画布

skew(float sx, float sy):sx,sy倾斜度

RectF r = new RectF(200, 200, 400, 500);
canvas.drawRect(r, paint);
paint.setColor(Color.BLUE);
canvas.skew(1.73f, 0);
canvas.drawRect(r, paint);

效果图.png

裁剪画布

clipRect(@NonNull Rect rect) rect:裁剪的矩形区域

RectF r = new RectF(200, 200, 400, 500);
canvas.drawRect(r, paint);
paint.setColor(Color.BLUE);
canvas.clipRect(new Rect(250, 250, 300, 400));
canvas.drawColor(Color.YELLOW);

效果图.png

理解canvas

Canvas画布的正确的理解: 1)当canvas执行drawXXX的时候就会新建一个新的画布图层

2)虽然后面新建了一个画布图层,但是还是会沿用之前设置的平移变换。不可逆的。(save和restore来解决)