Android自定义View你所要知道的(二):Canvas解析

在2D绘图中,Canvas和Paint能画出各种各样漂亮的图形。再配合着滑动和动画特效,就能做出非常炫酷的View。这篇文章是对使用Canvas绘图使用的总结。更像是对API的中文翻译。。

先从最小的画点开始:

 
 
 
 
public void drawPoint(float x, float y,Paint paint);
 
 
 
 
public void drawPoints(float[] pts, Paint paint);
public void drawPoints(float[] pts, int offset, int count,Paint paint);

参数:相对View自身的x,y坐标和画笔(Paint)。drawPoints()画多个点,以数组的形式存储多个点的坐标。

对坐标不是很了解的,可以参考我的上一篇文章: Android自定义View你所要知道的(一):坐标系

单个点:

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    canvas.drawPoint(100,100,mTestPaint);
}

效果图:


在创建Paint对象的时候记得设置宽度,否则画出来看不见,同理点的大小也是由Paint的宽度决定的。

画多个点:

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    float[] coordinates = new float[]{100,100,200,200,300,300,400,400,500,500};
    canvas.drawPoints(coordinates,mTestPaint);
}
效果:


在第三个方法,drawPoints(float[] pts, int offset, int count,Paint paint)中多了两个参数,offset和count。

offset参数指的是,前面pts坐标集中要从头要跳过的个数;count参数则是跳过后要执行几个值。我们以上面那串代码为例,传入offset和count 的值。

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    float[] coordinates = new float[]{100,100,200,200,300,300,400,400,500,500};
    canvas.drawPoints(coordinates,2,8,mTestPaint);
}

跳过前面两个,100,100,执行后面全部8个。效果如下:



绘制线

public void drawLine(float startX, float startY, float stopX, float stopY, Paint paint);
 
 
public void drawLines(float[] pts, Paint paint);
public void drawLines(float[] pts, int offset, int count, Paint paint);

画线和画点有着异曲同工之妙,不同的是一条线,他是由两个坐标点来确定的。

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    canvas.drawLine(100,100,500,500,mTestPaint);
}
效果:



画多条线,offset,count参数都和画点一样,参考多试试。

绘制矩形

public void drawRect(float left, float top, float right, float bottom,Paint paint) 
public void drawRect(Rect r, Paint paint)
public void drawRect(RectF rect, Paint paint)

参数都比较简单,通过左上右下的距离来构建一个矩形,同时也来确定绘制出来图形的大小。而下面两个方法是直接传入一个矩形对象来完成的,构造方法参数都一样。

public Rect(int left, int top, int right, int bottom)
public RectF(float left, float top, float right, float bottom)
相比可以看出,Rect和RectF的区别在于RectF参数为float类型,更加精确。

 
 
@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    canvas.drawRect(100,100,500,500,mTestPaint);
}

效果:

                

其实绘制矩形也像是通过确定2个坐标点来画的,如上右图。

构建Rect对象来画矩形:

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    Rect rect = new Rect(0,0,300,300);
    canvas.drawRect(rect,mTestPaint);
}

参数都一样,效果:

                   

当然,我们可以将画笔掏空(paint.setStyle(Paint.Style.STOKE)),这样画出来只有边线,效果如右上图.

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mTestPaint.setStyle(Paint.Style.STROKE);
Rect rect = new Rect(0,0,300,300);
canvas.drawRect(rect,mTestPaint);
}

绘制圆

public void drawCircle(float cx, float cy, float radius, Paint paint);

参数传入圆心的坐标和半径就可以了。如下:

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mTestPaint.setStyle(Paint.Style.STROKE);
canvas.drawCircle(500,500,200,mTestPaint);
}

                      


绘制椭圆

public void drawOval(RectF oval, Paint paint);

public void drawOval(float left, float top, float right, float bottom, Paint paint);

参数比较简单,直接看代码效果

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mTestPaint.setStyle(Paint.Style.STROKE);
canvas.drawOval(200,200,600,500,mTestPaint);
}


相信大家现在对距离传参和直接构建Rect矩形对象来绘制图形都比较了解。下面接不做过多的介绍了。


绘制圆角矩形

public void drawRoundRect(float left, float top, float right, float bottom, float rx, float ry, Paint paint)
public void drawRoundRect(RectF rect, float rx, float ry, Paint paint)

参数就比绘制矩形多了两个rx,ry。用来确定4个角,两个方向x,y的圆角半径。

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    canvas.drawRoundRect(200,200,600,600,90,90,mTestPaint);
}
效果:



绘制弧形

public void drawArc(float left, float top, float right, float bottom, float startAngle, float sweepAngle, boolean useCenter, Paint paint);
public void drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint);

相比前面所涉及到的参数出现了3个陌生的参数,startAngle,sweepAngle,usecenter。通过字面意思可以看出,开始的角度以及要扫描覆盖多少角度,boolean类型的usecenter直译是使用中心,待会试试两种不同的效果。

代码:

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawArc(300,300,800,800,0,300,true,mTestPaint);
}

先传入2个坐标距离,来确定弧形的大小,从0°开始沿着顺时针方向绘制300度。

绘制出来的效果:

                   

我们将usecenter改为false,效果  


两者之间的差距就在于,usecenter为true时会根据 弧形中心点  ,起始角度点,扫描度数结束的点来构建弧形。为false时,直接以起始点和结束点来绘制弧形。这就很好的理解参数名字。

将画笔掏空后,没有颜色填充的效果。

 
  
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mTestPaint.setStyle(Paint.Style.STROKE);
canvas.drawArc(300,300,800,800,0,300,false,mTestPaint);
}

                      

利用Path绘制多边形

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mTestPaint.setStyle(Paint.Style.STROKE);
Path path = new Path();
path.moveTo(200,200);
path.lineTo(200,500);
path.lineTo(500,500);
path.lineTo(500,200);
path.close();
canvas.drawPath(path,mTestPaint);
}

效果:

                        

通过4个点的坐标来绘制了一个正方形,close()方法的作用在于将第一个点和最后一个点连接,对图形进行闭合。

也可以在Path上添加其他的图形:


 
  
path.addCircle(350,350,80,Path.Direction.CW);
path.addCircle(350,350,40,Path.Direction.CW);

最后一个参数是枚举类型,就两个常量,CW和CCW。代表着顺时针和逆时针方向。

效果:



绘制文字

public void drawText(String text, int start, int end, float x, float y, Paint paint)

public void drawText(char[] text, int index, int count, float x, float y, Paint paint)

public void drawText(CharSequence text, int start, int end, float x, float y, Paint paint)

public void drawText(String text, float x, float y, Paint paint)

参数都比较简单,文字内容,坐标位置,文字内容中开始索引,结束索引, count参数:确定开始索引位置后需要从文字内容中执行几个数据;

需要值得注意的是,Java中取一段范围的数据,start和end。start包括这个索引的数据,而end不包括这个索引的数据。

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mTestPaint.setTextSize(50);
canvas.drawText("你好,欢迎来到英雄联盟!",0,5,500,500,mTestPaint);
}

效果:


将多个文字放在不同的点上:

public void drawPosText(String text,float[] pos, Paint paint)

public void drawPosText(char[] text, int index, int count, float[] pos, Paint paint)

pos数组参数,点的坐标。index和count跟上面说的一样起始索引和数量。

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mTestPaint.setTextSize(50);
char[] data = {'欢','迎','来','到','英','雄','联','盟'};
float[] pos = {200,200,300,300,400,400,500,500,600,600,700,700,800,800,900,900};
canvas.drawPosText(data,0,8,pos,mTestPaint);
}

效果:



前面我们说过path里再添加其他图形,这儿我们沿着Path添加的图形来绘制的文字:

 
  
public void drawTextOnPath( String text, Path path, float hOffset, float vOffset, Paint paint);

public void drawTextOnPath(char[] text, int index, int count, Path path, float hOffset, float vOffset,Paint paint);

代码实现以下

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mTestPaint.setTextSize(50);
mTestPaint.setStyle(Paint.Style.STROKE);
Path path = new Path();
path.addCircle(500,500,200, Path.Direction.CCW);
canvas.drawPath(path,mTestPaint);
canvas.drawTextOnPath("欢迎来到英雄联盟",path,0,200,mTestPaint);
}

不同的参数hOffset,vOffset;Offset跟绘制弧形startAngle参数是一个概念,起始角度位置。vOffset指的是距离添加图形边的偏移量。

效果:

                         


Canvas的剪裁功能:



可以直接剪裁一个矩形的图片,或者使用path构建多边形来剪裁。

 
  
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mTestPaint.setTextSize(50);
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.yjx);
Path path = new Path();
path.moveTo(200,200);
path.lineTo(200,800);
path.lineTo(800,800);
path.close();
canvas.clipPath(path);
canvas.drawBitmap(bitmap,0,0,mTestPaint);
}

效果:

                                              原图:  



差不多到这儿了。

更多解析:

android canvas常用的方法解析(一)







猜你喜欢

转载自blog.csdn.net/sinat_35938012/article/details/72786738