画图
像我们平时画图一样,需要纸和笔。Paint就是相当于笔,而Canvas就是纸,这里叫做画布。
凡是跟要画的东西的设置相关,比如大小,粗细,画笔颜色,透明度,字体的样式等等,都是在Paint里设置;同样,凡是要画出成品的东西,比如圆形,矩形,文字等相关的都是在Canvas里生成。
Paint
Paint基本设置函数:
方法 | 解释 |
---|---|
paint.setAntiAlias(boolean aa) | 设置是否使用抗锯齿功能,取值为true和false。取值为true,启用抗锯齿功能。如果使用抗锯齿功能,会使绘图速度变慢。 |
mPaint.setShader(Shader shader); | |
mPaint.setColor(int color); | 设置画笔颜色。 |
mPaint.setTextSize(float textSize); | 设置文字大小。 |
mPaint.setStrokeWidth(float width); | 设置画笔宽度。 |
mPaint.setStyle(Paint.Style style); | 设置绘图样式,可取值为Paint.Style.FILL(填充)、Paint.Style.STROKE(描边)、Paint.Style.FILL_AND_STROKE(填充加描边); |
mPaint.setTextAlign(Paint.Align align) | 设置文字对齐方式,取值为Paint.Align.LEFT(居左对齐)、Paint.Align.CENTER(居中对齐)、Paint.Align.RIGHT(居右对齐)。 |
mPaint.setStrokeCap(Paint.Cap cap) | 设置线帽样式,取值有Paint.Cap.ROUND(圆形线帽)、Paint.Cap.SQUARE(方形线帽)、Paint.Cap.BUTT(无线帽)。 |
mPaint.setAlpha(int a) | 设置透明度。 |
mPaint.setARGB(int a,int r,int g,int b) | 设置颜色。 |
mPaint.setColorFilter(ColorFilter filter) | |
mPaint.setDither(boolean dither); | |
mPaint.setElegantTextHeight(boolean elegant); | |
mPaint.setFakeBoldText(boolean fakeBoldText); | 设置是否为粗体文字,取值为true、false;取值为true,显示为粗体。 |
mPaint.setFilterBitmap(boolean filter); | |
mPaint.setFlags(int flags); | |
mPaint.setFontFeatureSettings(String settings); | |
mPaint.setFontVariationSettings(String fontVariationSettings); | |
mPaint.setHinting(int mode); | |
mPaint.setLetterSpacing(float letterSpacing); | |
mPaint.setLinearText(boolean linearText) | 设置是否打开线性文本标识。设置为true,即不进行文本缓存,能够节省内存空间,但是这是以显示速度为代价的。目前来说,这个需要的内存已经不足为虑了。 |
mPaint.setMaskFilter(MaskFilter maskFilter); | |
mPaint.setPathEffect(PathEffect effect) | 设置路径样式,取值类型是PathEffect的子类:ComposePathEffect、CornerPathEffect、DashPathEffect、DiscretePathEffect、PathDashPathEffect、SumPathEffect。 |
mPaint.reset() | 重置画笔。 |
mPaint.setShadowLayer(float radius, float dx, float dy, int shadowColor); | |
mPaint.setStrikeThruText(boolean strikeThruText); | 设置是否带有删除线效果,可取值为true、false;取值为true,显示删除线效果。 |
mPaint.setStrokeJoin(Paint.Join join) | 设置线段连接处样式,取值有:Paint.Join.MITER(结合处为锐角)、Paint.Join.ROUND(结合处为圆弧)、Paint.Join.BEVEL(结合处为直线)。 |
mPaint.setStrokeMiter(float miter) | 设置画笔的倾斜度。 |
mPaint.setSubpixelText(boolean subpixelText) | 设置是否打开亚像素来绘制文本。打开亚像素显示,可以增强文本显示清晰度,也会耗费一定的性能。 |
mPaint.setTextLocale(Locale locale); | |
mPaint.setTextScaleX(float scaleX); | 设置水平方向拉伸,不会影响高度。 |
mPaint.setTextLocales(LocaleList locales); | |
mPaint.setTextSkewX(float skewX); | 设置字体水平倾斜度,普通斜体字时-0.25。数值小于0是向右倾斜,数值大于0是向左倾斜。 |
mPaint.setTypeface(Typeface typeface); | 设置字体样式。mPaint.setUnderlineText(boolean underlineText); |
mPaint.setXfermode(Xfermode xfermode); | 待编写 |
字体样式设置(Typeface)
Typeface是专门用来设置字体样式的,通过paint.setTypeface()来指定。可以指定系统中的字体样式,也可以在指定自定义的样式文件中获取。要构建Typeface时,可以指定所用样式的正常体、斜体、粗体等,如果指定样式中,没有相关文字的样式就会用系统默认的样式来显示,一般默认是宋体。
创建Typeface:
方法 | 解释 |
---|---|
Typeface create(String familyName, int style) | 直接通过指定字体名来加载系统中自带的文字样式 |
Typeface create(Typeface family, int style) | 通过其它Typeface变量来构建文字样式 |
Typeface createFromAsset(AssetManager mgr, String path) | 通过从Asset中获取外部字体来显示字体样式 |
Typeface createFromFile(String path) | 直接从路径创建 |
Typeface createFromFile(File path) | 从外部路径来创建字体样式 |
Typeface defaultFromStyle(int style) | 创建默认字体 |
上面的方法中用到的style参数,其枚举值如下:
枚举值 | 解释 |
---|---|
Typeface.NORMAL | 正常体 |
Typeface.BOLD | 粗体 |
Typeface.ITALIC | 斜体 |
Typeface.BOLD_ITALIC | 粗斜体 |
Canvas
基本几何图形绘制
- 画直线:
void drawLine(float startX,float startY,float stopX,float stopY,Paint paint)
startX:开始点X坐标,startY:开始点Y坐标,stopX:结束点X坐标,stopY:结束点Y坐标; - 画多条直线:
void drawLines(float[] pts,Paint paint)
void drawLines(float[] pts,int offset,int count,Paint paint)
pts:是点的集合,大家下面可以看到,这里不是形成连接线,而是每两个点形成一条直线,pts的组织方式为{x1,y1,x2,y2,x3,y3,……} - 画点:
void drawPoint (float x, float y, Paint paint)
float X:点的X坐标,float Y:点的Y坐标 - 画多个点:
void drawPoints (float[] pts, Paint paint)
void drawPoints (float[] pts, int offset, int count, Paint paint)
float[] pts:点的合集,与上面直线一样,样式为{x1,y1,x2,y2,x3,y3,……}。int offset:集合中跳过的数值个数,注意不是点的个数!一个点是两个数值;count:参与绘制的数值的个数,指pts[]里人数值个数,而不是点的个数,因为一个点是两个数值。 - 画矩形:
void drawRect (float left, float top, float right, float bottom, Paint paint)
void drawRect (RectF rect, Paint paint)
void drawRect (Rect r, Paint paint)
第一个的写法是直接传入矩形的四个点,画出矩形;第二、三个构造函数是根据传入RectF或者Rect矩形变量来指定所画的矩形的。 - 画圆角矩形:
void drawRoundRect(RectF rect, float rx, float ry, Paint paint)
RectF rect:要画的矩形。float rx:生成圆角的椭圆的X轴半径,float ry:生成圆角的椭圆的Y轴半径。 - 画圆形:
void drawCircle (float cx, float cy, float radius, Paint paint)
RectF rect:要画的矩形。float rx:生成圆角的椭圆的X轴半径,float ry:生成圆角的椭圆的Y轴半径。 - 画椭圆形:
void drawOval (RectF oval, Paint paint)
椭圆是根据矩形生成的,以矩形的长为椭圆的X轴,矩形的宽为椭圆的Y轴,建立的椭圆图形。RectF oval:用来生成椭圆的矩形。 - 画弧:
void drawArc (RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint)
RectF oval:生成椭圆的矩形,float startAngle:弧开始的角度,以X轴正方向为0度,float sweepAngle:弧持续的角度,boolean useCenter:是否有弧的两边,取值为true,会画上两个边,取值为false,只有一条弧。 - 画文字:
void drawText (String text, float x, float y, Paint paint)
void drawText (CharSequence text, int start, int end, float x, float y, Paint paint)
void drawText (String text, int start, int end, float x, float y, Paint paint)
void drawText (char[] text, int index, int count, float x, float y, Paint paint)
第一个构造函数:最普通简单的构造函数;
第三、四个构造函数:实现截取一部分字体;
第二个构造函数中,可以传入charSequence类型的字符串,charSequence是可以利用spannableString来构造有图片的字符串的,那这里是不是可以画出带有图片的字符串来呢 ,我想多了,实际证明,canvas画图是不支持Span替换的。所以这里的charSequence跟普通的String没有任何区别的。 - 画文字时指定文字位置:
void drawPosText (char[] text, int index, int count, float[] pos, Paint paint)
void drawPosText (String text, float[] pos, Paint paint)
第一个构造函数,实现截取一部分文字绘制。第二个构造函数,绘制所有文字。
参数说明:
char[] text:要绘制的文字数组
int index::第一个要绘制的文字的索引
int count:要绘制的文字的个数,用来算最后一个文字的位置,从第一个绘制的文字开始算起
float[] pos:每个字体的位置,同样两两一组,如{x1,y1,x2,y2,x3,y3……} - 画文字时沿路径绘制:
void drawTextOnPath (String text, Path path, float hOffset, float vOffset, Paint paint)
void drawTextOnPath (char[] text, int index, int count, Path path, float hOffset, float vOffset, Paint paint)
参数说明:
float hOffset : 与路径起始点的水平偏移距离
float vOffset : 与路径中心的垂直偏移量
canvas变换与操作
Canvas是一个很虚幻的概念,相当于一个透明图层,每次Canvas画图时(即调用drawXxx()系列函数),都会产生一个透明图层,然后在这个图层上画图,画完之后覆盖在屏幕上显示。
如果在drawXxx()前,调用平移、旋转等函数来对Canvas进行了操作,那么这个操作是不可逆的。每次产生的画布的最新位置都是这些操作后的位置。
在Canvas与屏幕合成时,超出屏幕范围的图像是不会显示出来的。
- 平移:
void translate(float dx, float dy)
参数说明:
float dx:水平方向平移的距离,正数指向正方向(向右)平移的量,负数为向负方向(向左)平移的量;
flaot dy:垂直方向平移的距离,正数指向正方向(向下)平移的量,负数为向负方向(向上)平移的量; - 旋转:
void rotate(float degrees)
void rotate (float degrees, float px, float py)
参数说明:
第一个构造函数直接输入旋转的度数,正数是顺时针旋转,负数指逆时针旋转,它的旋转中心点是原点(0,0);
第二个构造函数除了度数以外,还可以指定旋转的中心点坐标(px,py); - 缩放:
public void scale (float sx, float sy)
public final void scale (float sx, float sy, float px, float py)
参数说明:
第一个构造函数:
float sy:垂直方向伸缩的比例,原始值为1,所以小于1的值为缩小,大于1的值为放大;
float sx:水平方向伸缩的比例,原始值为1,所以小于1的值为缩小,大于1的值为放大;
第二个构造函数:
float sy:垂直方向伸缩的比例,原始值为1,所以小于1的值为缩小,大于1的值为放大;
float sx:水平方向伸缩的比例,原始值为1,所以小于1的值为缩小,大于1的值为放大;
(float px,float py):进行画布缩放时轴心点的位置坐标。 - 扭曲(斜切):
void skew (float sx, float sy)
参数说明:
float sx:将画布在x方向上倾斜相应的角度,sx倾斜角度的tan值;
float sy:将画布在y轴方向上倾斜相应的角度,sy为倾斜角度的tan值; - 裁剪(clipXxx()系列函数):
裁剪画布是利用Clip系列函数,通过与Rect、Path、Region取交、并、差等集合运算来获得最新的画布形状。除了调用Save、Restore函数以外,这个操作是不可逆的,一但Canvas画布被裁剪,就不能再被恢复!
方法 |
---|
boolean clipPath(Path path) |
boolean clipPath(Path path, Region.Op op) |
boolean clipRect(Rect rect, Region.Op op) |
boolean clipRect(RectF rect, Region.Op op) |
boolean clipRect(int left, int top, int right, int bottom) |
boolean clipRect(float left, float top, float right, float bottom) |
boolean clipRect(RectF rect) |
boolean clipRect(float left, float top, float right, float bottom, Region.Op op) |
boolean clipRect(Rect rect) |
boolean clipRegion(Region region) |
boolean clipRegion(Region region, Region.Op op) |
- 画布的保存和恢复:
前面我们讲的所有对画布的操作都是不可逆的,这会造成很多麻烦,比如,我们为了实现一些效果不得不对画布进行操作,但操作完了,画布状态也改变了,这会严重影响到后面的画图操作。如果我们能对画布的大小和状态(旋转角度、扭曲等)进行实时保存和恢复就最好了。
int save ()
void restore()
Save():每次调用Save()函数,都会把当前的画布的状态进行保存,然后放入特定的栈中;
restore():每当调用Restore()函数,就会把栈中最顶层的画布状态取出来,并按照这个状态恢复当前的画布,并在这个画布上做画。
如何获取一个Canvas对象
- 自定义View时,重写onDraw()或dispatchDraw()方法:
在onDraw、dispatchDraw在传入的参数中都有一个canvas对象。这个canvas对象是View中的Canvas对象,利用这个canvas对象绘图,效果会直接反应在View中;
onDraw()的意思是绘制视图自身;
dispatchDraw()是绘制子视图。
无论是View还是ViewGroup,这两个方法都是存在的,他们的调用顺序都是onDraw()->dispatchDraw()。但是在ViewGroup中,当它有背景的时候就会调用onDraw()方法,否则就会跳过onDraw()方法直接调用dispatchDraw()方法。所以,如果是在ViewGroup中绘图,往往是重写dispatchDraw()方法;在View中,onDraw()和dispatchDraw()都会被调用,所以我们无论是把绘图代码放在onDraw()还是dispatchDraw()中都是可以得到效果的,但是由于dispatchDraw()的含义是绘制子控件,所以,在绘制View控件时,我们是重写onDraw()方法。
一般情况下,在绘制View控件时,重写onDraw()方法,在绘制ViewGroup时,重写dispatchDraw()方法。 - 使用Bitmap创建:
矩形工具类RectF与Rect
这两个都是矩形辅助类,区别不大,用哪个都行,只是Rect用的int型的值,RectF用的是float型的值。根据四个点构建一个矩形结构;在画图时,利用这个矩形结构可以画出对应的矩形或者与其它图形Region相交、相加等等;
RectF:构造函数有四个,但最常用的是第二个,根据四个点构造出一个矩形;
方法 | 解释 |
---|---|
RectF() | |
RectF(float left, float top, float right, float bottom) | 左上角的坐标和右下角的坐标 |
RectF(RectF r) | |
RectF(Rect r) |
Rect:构造函数有三个;
方法 | 解释 |
---|---|
Rect() | |
Rect(int left, int top, int right, int bottom) | 左上角的坐标和右下角的坐标 |
Rect(Rect r) |
Path
在canvas中绘制路径:void drawPath(Path path,Paint paint)
- 直线路径:
void moveTo(float x1,float y1):绘制直线的开始点,即将直线路径的绘制点定在(x1,y1)的位置;
void lineTo (float x2, float y2):直线的结束点,又是下一次绘制直线路径的开始点;lineTo()可以一直用;
void close ():如果连续画了几条直线,但没有形成闭环,调用Close()会将路径首尾点连接起来,形成闭环; - 矩形路径:
void addRect (float left, float top, float right, float bottom, Path.Direction dir)
void addRect (RectF rect, Path.Direction dir)
这里Path类创建矩形路径的参数与在canvas绘制矩形差不多,唯一不同的一点是增加了Path.Direction参数;
Path.Direction有两个值:
Path.Direction.CCW:是counter-clockwise缩写,指创建逆时针方向的矩形路径;
Path.Direction.CW:是clockwise的缩写,指创建顺时针方向的矩形路径;
无论正时针还是逆时针,仅仅是生成方式不同而已,矩形就那么大画出来的路径矩形当然与矩形一样大了。生成方式的区别在于,依据生成方向排版的文字!后面我们会讲到文字,文字是可以依据路径排版的,那文字的行走方向就是依据路径的生成方向; - 圆角矩形路径:
void addRoundRect (RectF rect, float[] radii, Path.Direction dir)
void addRoundRect (RectF rect, float rx, float ry, Path.Direction dir)
第一个构造函数:可以定制每个角的圆角大小:
float[] radii:必须传入8个数值,分四组,分别对应每个角所使用的椭圆的横轴半径和纵轴半径,如{x1,y1,x2,y2,x3,y3,x4,y4},其中,x1,y1对应第一个角的(左上角)用来产生圆角的椭圆的横轴半径和纵轴半径,其它类推……
第二个构造函数:只能构建统一圆角大小
float rx:所产生圆角的椭圆的横轴半径;
float ry:所产生圆角的椭圆的纵轴半径; - 圆形路径:
void addCircle (float x, float y, float radius, Path.Direction dir)
参数说明:
float x:圆心X轴坐标;
float y:圆心Y轴坐标;
float radius:圆半径。 - 椭圆路径:
void addOval (RectF oval, Path.Direction dir)
参数说明:
RectF oval:生成椭圆所对应的矩形
Path.Direction :生成方式,与矩形一样,分为顺时针与逆时针,意义完全相同,不再重复 - 弧形路径:
void addArc (RectF oval, float startAngle, float sweepAngle)
参数说明:
RectF oval:弧是椭圆的一部分,这个参数就是生成椭圆所对应的矩形;
float startAngle:开始的角度,X轴正方向为0度;
float sweepAngel:持续的度数; - 线段轨迹:
void quadTo (float x1, float y1, float x2, float y2)
贝塞尔曲线
- 二阶贝塞尔曲线:
二阶贝塞尔曲线在Android中的API为:quadTo()和rQuadTo(),这两个API在原理上是可以相互转换的。quadTo()是基于绝对坐标,而rQuadTo()是基于相对坐标的。
void quadTo(float x1, float y1, float x2, float y2)
void rQuadTo(float dx1, float dy1, float dx2, float dy2)
绘制流程
- ViewGroup的绘制流程:
View和ViewGroup基本相同,只是在ViewGroup中不仅要绘制自己还要绘制其中的子控件,而View则只需要绘制自己就可以了。
绘制流程分为三步:测量、布局、绘制。
onMeasure():测量自己的大小,为正式布局提供建议。(注意:只是建议,至于用不用,要看onLayout()方法);
onLayout():使用layout()方法对所有子控件布局;
onDraw():根据布局的位置绘图;
-
-
-
-
-
-
-
-
-
-
-
-
-
-
last line for now