Canvas:画布
* The Canvas class holds the "draw" calls. To draw something, you need
* 4 basic components: A Bitmap to hold the pixels, a Canvas to host
* the draw calls (writing into the bitmap), a drawing primitive (e.g. Rect,
* Path, text, Bitmap), and a paint (to describe the colors and styles for the
* drawing)
译文:
Canvas类保存“draw”调用。要绘制一些东西,您需要4个基本组件:一个用于保存像素的位图、一个用于承载绘制调用(写入位图)的画布、一个绘图原语(例如矩形、路径、文本、位图)和一个油漆(用于描述图纸)
我们常见的理解属于一个画布,只要作画就需要画布,至于在画布上画什么,由参与者自己决定。
图形组合:
任何图形都可以通过点、线、面来完成,如何做到完美的绘画者,我们需要知道Canvas的api都提供了什么,他能干什么
作画需要什么?
1.笔:Paint
2.画布:Canvas
有了笔和画笔,基本可以画很多东西。
Paint
画笔提供了最基础的绘画功能,颜色、画笔大小、样式等。我们只需要简单的设计几个参数就可以使用
- setColor(); //设置画笔的颜色
- setAntiAlias(); //设置画笔的锯齿效果
- setARGB(); //设置画笔的A、R、G、B值
- setAlpha(); //设置画笔的Alpha值
- setTextSize(); //设置字体的尺寸
- setStyle(); //设置画笔的风格(空心或实心)
- setStrokeWidth(); //设置空心边框的宽度
有这几种参数,基本就可以完成笔的设置,如果想个性化画笔,可以参考其他Paint的API
Canvas 常用的API的介绍:
1.绘画矩形:drawArc
public void drawArc(@NonNull RectF oval, float startAngle, float sweepAngle, boolean useCenter, @NonNull Paint paint)
RectF :画布的大小
startAngle: 开始角度,这个值只能决定图形的开始角度,不能改变图的开角角度。
sweepAngle:扫描的角度,正常就是图形的角度
useCenter:是否以中心旋转,如果是,画中的扇形中心在圆中心,否则就是一个普通的扇形
paint:画笔
1.1拼色扇形
在一些统计图中,我们经常看到百分比的统计图,这是怎么做到的呢?其实这类图做法也是通过绘制图形完成,但是绘制的时候需要注意图层问题。
注意1.Canvas是一层一层绘制的,如果处理多图形拼图,最大层应该在最下方。
RectF rectF = new RectF(0, 0, getMeasuredWidth(), getMeasuredHeight());
if (paint == null) {
paint = new Paint();
}
paint.setColor(Color.RED);
paint.setStrokeWidth(2);
paint.setStyle(Paint.Style.FILL);
canvas.drawArc(rectF, 0, 360, true, paint);
canvas.save();
paint.setColor(Color.YELLOW);
canvas.drawArc(rectF, 0, 150, true, paint);
paint.setColor(Color.BLUE);
canvas.drawArc(rectF, 0, 90, true, paint);
paint.setColor(Color.GRAY);
canvas.drawArc(rectF, 0, 30, true, paint);
这里面有四种扇形,红色、黄色、绿色、灰色
灰色开角:30
绿色开角:90
黄色开角:150
红色开角:360(圆形)
视觉上:
灰色:30°
绿色:60°
黄色:60°
红色:210°
技巧:
先算出各个角度,再计算出各个扇形的开角。注意先绘制大图形,再绘制小的,否则360°先绘制会导致图形的遮挡问题
1.2绘制路径:drawPath
public void drawPath(@NonNull Path path, @NonNull Paint paint)
path:路径值,又因为path可以完成各种路径的构建,关于path会单独讲解
正常path绘制很多东西,如果组成一个画面由三个点
paint:画笔
private void drawPath(Canvas canvas) {
Path path = new Path();
path.moveTo(100, 100);
path.lineTo(300, 300);
path.lineTo(200,300);
path.close();
canvas.drawPath(path, paint);
}
1.3组合绘图,绘制复杂的图形或者需要耗时较长,可以通过该方法:drawPicture
public void drawPicture(@NonNull Picture picture)
picture:图片或者海报
1.4 绘制色块,这个色块类似一个填充色,以ARGB颜色来完成drawARGB
public void drawARGB(int a, int r, int g, int b)
a:透明度
r:红色
g:绿色
b:蓝色
值可以参考色值:0-255,2^8-1
1.4-1绘制bitmap资源:drawBitmap
public void drawBitmap(@NonNull Bitmap bitmap, float left, float top, @Nullable Paint paint)
bitmap:bitmap资源
left:从布局左边的坐标点,类似View的X轴
top:从布局的顶部的坐标点,类似View的Y轴
paint:画笔
private void drawBitmap(Canvas canvas)
{
canvas.drawBitmap(getBitmap(),0,0,paint);
canvas.save();
}
1.4图片扭曲特效:drawBitmapMesh
public void drawBitmapMesh(@NonNull Bitmap bitmap, int meshWidth, int meshHeight, @NonNull float[] verts, int vertOffset, @Nullable int[] colors, int colorOffset, @Nullable Paint paint)
参数:
1.bitmap:指定需要扭曲的源位图。
2.meshwidth:该参数控制在横向上把该源位图划分成多少格。
3.meshheight:该参数控制在纵向上把该源位图划分成多少格。
4.verts:该参数是一个长度为( meshwidth+1)(meshheight+1)2的数组,它记录了扭曲后的位图各“顶点”(网格线的交点)位置。虽然它是个一维数组,实际上它记录的数据是形如(x0,y0)、(x1,y1)、(x2,y2)、(xN,yN)格式的数据,这些数组元素控制对 bitmap位图的扭曲效果。
5.vertOffset:控制verts数组中从第几个数组元素开始才对 bitmap进行扭曲(忽略veroffset之前数据的扭曲效果)。
floa[] verts={(x1,y1)(x2,y2)},扭曲坐标点,奇数是y轴,偶数是x轴
1.5画圆:drawCircle
public void drawCircle(float cx, float cy, float radius, @NonNull Paint paint)
cx:圆心x轴坐标
cy:圆心y轴坐标
radius:半径
paint:画笔
canvas.drawCircle(100,100,100,paint);
1.5划线:drawLine
public void drawLine(float startX, float startY, float stopX, float stopY, @NonNull Paint paint)
private void drawLine(Canvas canvas) { paint.setStrokeWidth(100); canvas.drawLine(0, 500, 500, 500, paint); }
startX:起点x坐标
startY:起点y坐标
stopX:终点x坐标
stopY:终点y坐标
paint:画笔
由于线段是两点确定,所以(startX,startY)是起点,(stopX,stopY)是重点
如果想这条线很宽。通过设置画笔的宽度 paint.setStrokeWidth(100);
1.6画椭圆:drawOval
public void drawOval(@NonNull RectF oval, @NonNull Paint paint)
public void drawOval(float left, float top, float right, float bottom, @NonNull Paint paint)
oval(left,top,right,buttom):椭圆的画布
private void drawOval(Canvas canvas) {
int width=getMeasuredWidth();
int height=getMeasuredHeight()/3;
canvas.drawOval(0,0,width,height,paint);
}
1.7绘制画笔:drawPaint
public void drawPaint(@NonNull Paint paint)
paint:这个画笔绘制出来就是当前view的颜色,填充满整个画布
private void drawPaint(Canvas canvas) {
canvas.drawPaint(paint);
}
1.8绘制补丁:drawPatch
public void drawPatch(@NonNull NinePatch patch, @NonNull Rect dst, @Nullable Paint paint)
NinePatch :点九资源
Rect :绘制区域
Bitmap bitmap=getBitmap(); NinePatch patch=new NinePatch(bitmap,bitmap.getNinePatchChunk());
1.9绘制点:drawPoint
public void drawPoint(float x, float y, @NonNull Paint paint)
x:点的x轴坐标
y:点的y轴
点的大小取决于paint的画笔
private void drawPoint(Canvas canvas) {
paint.setStrokeWidth(20);
canvas.drawPoint(100, 100, paint);
}
1.10绘制文字从点pos出发:drawPosText
public void drawPosText(@NonNull String text, @NonNull @Size(multiple = 2) float[] pos, @NonNull Paint paint)
private void drawPosText(Canvas canvas) {
float[] pos = new float[]{100, 100};
canvas.drawPosText("Hellow", pos, paint);
}
float[] pos:坐标,(x,y)
1.11绘制矩形区域:drawRect
public void drawRect(@NonNull RectF rect, @NonNull Paint paint)
RectF :绘制区域
private void drawRect(Canvas canvas) {
RectF rectF=new RectF(0,0,500,500);
canvas.drawRect(rectF,paint);
}
1.12绘制色域:drawRGB
public void drawRGB(int r, int g, int b)
public void drawColor(@ColorInt int color) {
nDrawColor(mNativeCanvasWrapper, color, PorterDuff.Mode.SRC_OVER.nativeInt);
}
一般绘制单个对象,如果不指定区域,默认大小是当前view的宽和高
public void drawRGB(Canvas canvas) {
canvas.drawRGB(200, 200, 200);
}
1.13在矩形内绘制圆角:drawRoundRect
public void drawRoundRect(@NonNull RectF rect, float rx, float ry, @NonNull Paint paint)
RectF :代表绘制区域
rx:圆角在在矩形内的坐标x轴
ry:圆角在在矩形内的坐标y轴
注意:如果rx和ry为0,那么绘制出来的圆角就会0,view就是矩形,如果rx,ry在矩形正中心,那么绘制出来的圆角就是圆形
1.如果x和y都小于矩形的宽和高,那么显示就是矩形四个角被裁剪
2.如果x和y都大于矩形的宽和高,那么显示就是圆
3.如果x和y存在一个小于宽和高,那么显示可能是一个不规则图形
public void drawRoundRect(Canvas canvas)
{
RectF rectF=new RectF(0,0,200,200);
canvas.drawRoundRect(rectF,10,10,paint);
}
1.14绘制字符:drawText
public void drawText(@NonNull String text, float x, float y, @NonNull Paint paint)
绘制的时候,paint style必须设置成paint.setStyle(Paint.Style.FILL);否则会出现一团
private void drawText(Canvas canvas)
{
paint.setTextSize(100);
canvas.drawText("你好",100,100,paint);
}
text:内容
x:位置的x轴坐标
y:位置的y轴坐标
解释:文字的样式和大小,都是通过paint来设置,关于paint可以自行查看
1.15绘制文本按路径显示:drawTextOnPath
public void drawTextOnPath(@NonNull String text, @NonNull Path path, float hOffset, float vOffset, @NonNull Paint paint)
* @param text The text to be drawn* @param path The path the text should follow for its baseline
* @param hOffset The distance along the path to add to the text's starting position
* @param vOffset The distance above(-) or below(+) the path to position the text
* @param paint The paint used for the text (e.g. color, size, style)
text :绘制的文本信息
path:路径,最终文本文字会按路径显示
hOffset :沿路径添加到文本起始位置的距离
vOffset :定位文本的路径上方(-)或下方(+)的距离
paint :画笔
private void drawTextOnPath(Canvas canvas) {
paint.setTextSize(100);
Path path=new Path();
path.moveTo(0,500);
path.lineTo(500,500);
path.lineTo(500,0);
path.close();
canvas.drawTextOnPath("Hello word just do it",path,100,100,paint);
}
1.16绘制运行中的文本:drawTextRun
public void drawTextRun(@NonNull CharSequence text, int start, int end, int contextStart, int contextEnd, float x, float y, boolean isRtl, @NonNull Paint paint)
* @param text the text to render* @param start the start of the text to render. Data before this position can be used for
* shaping context.
* @param end the end of the text to render. Data at or after this position can be used for
* shaping context.
* @param contextStart the index of the start of the shaping context
* @param contextEnd the index of the end of the shaping context
* @param x the x position at which to draw the text
* @param y the y position at which to draw the text
* @param isRtl whether the run is in RTL direction
* @param paint the paint
text:
start :内容开始索引
end :内容结束的索引
contextStart :塑造语境的起点索引,默认从0开始,
contextEnd 塑造语境的终结索引默认text的长度
isRtl :运行是否在RTL方向
(x ,y):坐标
private void drawTextRun(Canvas canvas)
{
paint.setTextSize(100);
CharSequence text="Hello word just do it";
canvas.drawTextRun(text,0,text.length(),0,text.length(),100,100,true,paint);
canvas.drawTextRun(text,0,text.length(),0,text.length(),100,600,false,paint);
}
1.17绘制顶点集合,绘制多边形:drawVertices
public void drawVertices(@NonNull VertexMode mode, int vertexCount, @NonNull float[] verts, int vertOffset, @Nullable float[] texs, int texOffset, @Nullable int[] colors,
int colorOffset, @Nullable short[] indices, int indexOffset, int indexCount,
@NonNull Paint paint)
1. mode: 如何解释顶点数组 2. vertexCount:顶点数组中的值数(如果非空,则为相应的texs和颜色数组)。每个逻辑顶点都是两个值(x,y),vertexCount必须是2的倍数 3. verts:网格的顶点数组 4. vertOffset:绘制前要跳过的顶点中的值数 5. texs:可能为空。如果不为空,则指定要采样到当前着色器中的坐标(例如位图平铺或渐变) 6. texOffset:绘制前要跳过的texs中的值数 7. colors:可能为空。如果不为空,则为每个顶点指定一种颜色,以便在三角形上进行插值。8. colorOffset:绘制前要跳过的颜色值的数目 9. indices:如果不为null,则引用到顶点(texs,colors)数组的索引数组 10. indexCount:索引数组中的条目数(如果不为空)。
二、最终总结表如下
Canvas的经常使用操作
操作类型 | 相关API | 备注 |
绘制颜色 | drawColor, drawRGB, drawARGB | 使用单一颜色填充整个画布 |
绘制基本形状 | drawPoint, drawPoints, drawLine, drawLines, drawRect, drawRoundRect, drawOval, drawCircle, drawArc | 依次为 点、线、矩形、圆角矩形、椭圆、圆、圆弧 |
绘制图片 | drawBitmap, drawPicture | 绘制位图和图片 |
绘制文本 | drawText, drawPosText, drawTextOnPath | 依次为 绘制文字、绘制文字时指定每一个文字位置、依据路径绘制文字 |
绘制路径 | drawPath | 绘制路径。绘制贝塞尔曲线时也须要用到该函数 |
顶点操作 | drawVertices, drawBitmapMesh | 通过对顶点操作能够使图像形变,drawVertices直接对画布作用、 drawBitmapMesh仅仅对绘制的Bitmap作用 |
画布剪裁 | clipPath, clipRect | 设置画布的显示区域 |
画布快照 | save, restore, saveLayerXxx, restoreToCount, getSaveCount | 依次为 保存当前状态、 回滚到上一次保存的状态、 保存图层状态、 回滚到指定状态、 获取保存次数 |
画布变换 | translate, scale, rotate, skew | 依次为 位移、缩放、 旋转、错切 |
Matrix(矩阵) | getMatrix, setMatrix, concat | 实际画布的位移。缩放等操作的都是图像矩阵Matrix,仅仅只是Matrix比較难以理解和使用。故封装了一些经常使用的方法。 |