Android自定义View之draw系方法

Canvas是Android绘制的基础,onDraw方法提供Canvas类来帮助开发者绘制内容,为了加强自己的印象做的总结,并且相当于自己的一份文档。

绘制的基本函数介绍:

1,drawCircle(float cx, float cy, float radius, Paint paint)     画圆

2,drawRect(float left, float top, float right, float bottom,  Paint paint)   画矩形

3,drawPoint(float x, float y, Paint paint)  画点

4,drawPoints( float[] pts, int offset, int count, Paint paint)   画多个点

5,drawOval(float left, float top, float right, float bottom, Paint paint)  画椭圆

6,drawLine(float startX, float startY, float stopX, float stopY, Paint paint) 画线

7,drawLines( float[] pts,  Paint paint) 画多条线

8,drawRoundRect(float left, float top, float right, float bottom, float rx, float ry, Paint paint)  圆角矩形

9,drawArc(float left, float top, float right, float bottom, float startAngle,
        float sweepAngle, boolean useCenter, Paint paint)   画弧形或者扇形

10,drawPath(@NonNull Path path, @NonNull Paint paint)  画路径

11,drawBitmap(Bitmap bitmap, float x, float y, Paint paint) 画图

12,drawText(String text, float x, float y, Paint paint) 画文字

一,圆

image.png

     Paint p = new Paint();
     canvas.drawColor(Color.YELLOW);
     p.setStyle(Paint.Style.STROKE);
     p.setStrokeWidth(20);
     canvas.drawCircle(100,100,50,p);

坐标是如何计算的呢?以圆为例子其他等同,可以看一下我写的关于View坐标系的总结。


image.png

二, 矩形

image.png

  @Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
     Paint p = new Paint();
     canvas.drawColor(Color.YELLOW);
     p.setStyle(Paint.Style.STROKE);
     p.setStrokeWidth(20);
     canvas.drawRect(100,100,300,300,p);
}

三, 点

image.png
 @Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
     Paint p = new Paint();
     canvas.drawColor(Color.YELLOW);
     p.setStyle(Paint.Style.STROKE);
     p.setStrokeCap(Paint.Cap.ROUND);
     p.setStrokeWidth(20);
     canvas.drawPoint(100,100,p);
}

四,多点

image.png
 @Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
     Paint p = new Paint();
     float[] points = {50, 50, 100, 100, 150, 150};
     canvas.drawColor(Color.YELLOW);
     p.setStyle(Paint.Style.STROKE);
     p.setStrokeCap(Paint.Cap.ROUND);
     p.setStrokeWidth(20);
     canvas.drawPoints(points,0,6,p);
}

五,椭圆

image.png

 @Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
     Paint p = new Paint();
     canvas.drawColor(Color.YELLOW);
     p.setStyle(Paint.Style.STROKE);
     canvas.drawOval(100,100,300,500,p);
}

六,线

image.png

 @Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
     Paint p = new Paint();
     canvas.drawColor(Color.YELLOW);
     p.setStyle(Paint.Style.STROKE);
     canvas.drawLine(100,100,300,300,p);
}

七,多线

image.png
@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
     Paint p = new Paint();
     float[] points ={100,100,300,300,300,100,100,300,500,200,600,300,600,300,700,100};
     canvas.drawColor(Color.YELLOW);
     p.setStyle(Paint.Style.STROKE);
     canvas.drawLines(points,p);
}

八,画圆角矩形

image.png
 @Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
     Paint p = new Paint();
     canvas.drawColor(Color.YELLOW);
     p.setStyle(Paint.Style.STROKE);
     canvas.drawRoundRect(100,100,800,500,30,30,p);
}

九,画弧或扇形

 @Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
     Paint p = new Paint();
     canvas.drawColor(Color.YELLOW);
     p.setStyle(Paint.Style.STROKE);
     //startAngle从椭圆的三点钟方向开始,顺时针画角度,负数则为逆时针,也就是说圆心的横向直径右侧顶点,sweepAngle是角度,360是一圈userCenter是代表是否连接圆心,也就是扇形
     canvas.drawArc(100,100,600,300,0,270,false,p);
}
image.png

参数改为连接圆心

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
     Paint p = new Paint();
     canvas.drawColor(Color.YELLOW);
     p.setStyle(Paint.Style.STROKE);
     //startAngle从椭圆的三点钟方向开始,顺时针画角度,负数则为逆时针,也就是说圆心的横向直径右侧顶点,sweepAngle是角度,360是一圈userCenter是代表是否连接圆心,也就是扇形
     canvas.drawArc(100,100,600,300,0,270,true,p);
}

话说,如果加上颜色有没有点饼状图的意思

十,画路径
先来一个自画像,总结一下基本的drawpath相关函数

image.png

   @Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
     Paint p = new Paint();
     Path path = new Path();
     canvas.drawColor(Color.YELLOW);
     p.setStyle(Paint.Style.STROKE);
    path.addRoundRect(100,100,400,300,30,30,Path.Direction.CCW);
    RectF rect1 = new RectF(150,150,200,200);
    path.arcTo(rect1,-180,180,true);
    RectF rect2 = new RectF(300,150,350,200);
    path.arcTo(rect2,-180,180,true);
    path.arcTo(175,100,325,250,30,120,true);
    path.moveTo(250,300);
    path.lineTo(250,600);
    path.arcTo(100,600,400,800,-180,180,true);
    path.moveTo(100,450);
    path.lineTo(400,450);
    canvas.drawPath(path,p);
}

Path相关API

1,path.add+图形

例如上文肖像的脸就是添加的一个圆角矩形,代码如下

path.addRoundRect(100,100,400,300,30,30,Path.Direction.CCW);

类似的还有其他的图形,在这里不赘述了。


image.png

2,path.lineTo(x,y)
从参数可以看到函数需要一个坐标,也就是你要把线画到哪里,以当前坐标为起点向目标点画线,目标即函数的x,y。

这里存在一个疑点,哪里是当前的位置,添加路径的时候我怎么知道绘制的终点也就是上个闭合图形的结束点在哪里?

弧形的起始点,我们刚才已经说过了,是3点钟方向,顺时针画弧线,那矩形呢?做个小验证吧。

image.png
path.addRect(100,100,400,300,Path.Direction.CW);
     path.lineTo(200,200);//画线
     canvas.drawPath(path,p);

可以看到左上顶点,很符合逻辑。无论是CW顺时针和CCW逆时针都是一样的。
3,path.moveTo(x,y)
移动当前绘制点,到一个x,y坐标。相当于你抬起画笔,移动到一个你想要的位置,不再赘述了。

4,path.quadTo & path.cubicTo 画曲线

quadTo(float dx1, float dy1, float dx2, float dy2)
cubicTo(float x1, float y1, float x2, float y2,float x3, float y3)

5,path. arcTo 追加弧度

arcTo(float left, float top, float right, float bottom, float startAngle,
        float sweepAngle, boolean forceMoveTo)

前面的参数很熟悉了,主要说一下forceMoveTo这个boolean值,如果为false,他会从当前位置拖到你开始画弧度的位置。

举个例子:

image.png
     path.addRoundRect(100,100,400,300,30,30,Path.Direction.CCW);
     path.arcTo(150,150,300,300,0,180,false); //画弧
     canvas.drawPath(path,p);

我的代码展示了我要画一个圆角矩形和一个弧形利用drawpath的方式,
你可以看到红色箭头指向的线条是从结束的画笔位置拖到三点钟的弧形画笔方向。forceMoveTo可以看到我们设置了false,当我们设置为true时就不会拖动过来了。我想你已经明白了。

image.png

临时小结
上面提到的path相关函数,有一些都有一个兄弟函数,函数名称头加r,具体是什么样子呢,

path.rLlineTo
path.rMoveTo
path.rQuadTo
path.rCubicTo

他们的含义就是不加r的函数是应用的绝对坐标,而加r的相对的是当前坐标点。

image.png
image.png
     path.addRoundRect(100,100,400,300,30,30,Path.Direction.CCW);
     path.lineTo(200,200);//画线

看到了吗?他是相对于View坐标系的话线,也就是说从图形圆角矩形的结束点向View坐标系的200,200画点,然后我们看一下把函数改为rLineTo:

image.png
 path.rLineTo(200,200);//画线

看到这里你应该已经明白了。他是相对于圆角矩形绘制结束点的200,200。其他函数等同,不再赘述了。

6,path.close() 封闭开口

image.png
 @Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
     Paint p = new Paint();
     Path path = new Path();
     canvas.drawColor(Color.YELLOW);
     p.setStyle(Paint.Style.STROKE);
     path.lineTo(400,0);//画线
     path.close();
     path.arcTo(150,150,300,300,0,180,true);
     path.close();
     canvas.drawPath(path,p);

第一个例子画了两条线,封闭了开口变为三角形,第二个例子封闭了弧形,变为半圆形。本质上就是为我们画了一条线。

十一,Bitmap图片

image.png
 @Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
     Paint p = new Paint();
     canvas.drawColor(Color.YELLOW);    
     Bitmap bitmap =BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher)     
     canvas.drawBitmap(bitmap,100,100,p);
}

十一,Text文字

image.png
     canvas.drawColor(Color.YELLOW);
     p.setTextSize(50);
     canvas.drawText("大家好我是aidl",100,100,p);

在我的学习过程中,我跟随了大神的个人博客,博客地址在本文的下方,有需要直接去学习就好了,还有我的View坐标系地址也在本文的下方,在我学习的博客中有练习,下面上两个练习,代码还是很拙,但是基本的实现了效果,下面贴一下完整代码和效果。

public class MyViewCanvasDraw extends View {


//步长
private static final int STEP = 50;

//文字数组
private static final String[] texts = {"阿里","腾讯","百度","小米","今日头条"};

//直方图值
private static final int[] values = {20,50,30,100,400};

//画笔
private Paint p;


public MyViewCanvasDraw(Context context) {
    super(context);
}


public MyViewCanvasDraw(Context context, @Nullable AttributeSet attrs) {
    super(context, attrs);
}


public MyViewCanvasDraw(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
}

{
    p=new Paint();
    p.setColor(Color.WHITE);
    p.setStrokeWidth(3);
}


@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    //绘制背景
    canvas.drawRGB(86,109,120);

    /**画坐标轴-----------------**/
    int width =getWidth();

    int height =getHeight();

    //以View的宽的10%来控制间距画线
    int PointPadding = width/10;

    float[] points ={PointPadding,PointPadding,PointPadding,height-PointPadding,PointPadding,height-PointPadding,width-PointPadding,height-PointPadding};

    canvas.drawLines(points,p);
    /**-------------------------**/

    /**画直方图-------------------**/
    p.setStyle(Paint.Style.FILL);
    p.setColor(Color.parseColor("#8BC34A"));
    p.setAntiAlias(true);

    for (int i=0;i
image.png

还有很多需要优化的地方,是一个简单的直方图的例子,最后感谢大神的无私奉献,下方我将贴上原文地址,给更多需要学习的人。

hencoder大神带路不迷路传送门

View坐标系传送门

你可能感兴趣的:(Android自定义View之draw系方法)