Paint类介绍
Paint即画笔,在绘图过程中起到了极其重要的作用,画笔主要保存了颜色, 样式等绘制信息,指定了如何绘制文本和图形,画笔对象有很多设置方法,大体上可以分为两类,一类与图形绘制相关,一类与文本绘制相关。
1.图形绘制
* setARGB(int a,int r,int g,int b);
设置绘制的颜色,a代表透明度,r,g,b代表颜色值。
* setAlpha(int a);
设置绘制图形的透明度。
* setColor(int color);
设置绘制的颜色,使用颜色值来表示,该颜色值包括透明度和RGB颜色。
* setAntiAlias(boolean aa);
设置是否使用抗锯齿功能,会消耗较大资源,绘制图形速度会变慢。
* setDither(boolean dither);
设定是否使用图像抖动处理,会使绘制出来的图片颜色更加平滑和饱满,图像更加清晰
* setFilterBitmap(boolean filter);
如果该项设置为true,则图像在动画进行中会滤掉对Bitmap图像的优化操作,加快显示速度,本设置项依赖于dither和xfermode的设置
* setMaskFilter(MaskFilter maskfilter);
设置MaskFilter,可以用不同的MaskFilter实现滤镜的效果,如滤化,立体等
* setColorFilter(ColorFilter colorfilter);
设置颜色过滤器,可以在绘制颜色时实现不用颜色的变换效果
* setPathEffect(PathEffect effect);
设置绘制路径的效果,如点画线等
* setShader(Shader shader);
设置图像效果,使用Shader可以绘制出各种渐变效果
* setShadowLayer(float radius ,float dx,float dy,int color);
在图形下面设置阴影层,产生阴影效果,radius为阴影的角度,dx和dy为阴影在x轴和y轴上的距离,color为阴影的颜色
* setStyle(Paint.Style style);
设置画笔的样式,为FILL,FILL_AND_STROKE,或STROKE
* setStrokeCap(Paint.Cap cap);
当画笔样式为STROKE或FILL_AND_STROKE时,设置笔刷的图形样式,如圆形样式 Cap.ROUND,或方形样式Cap.SQUARE
* setSrokeJoin(Paint.Join join);
设置绘制时各图形的结合方式,如平滑效果等
* setStrokeWidth(float width);
当画笔样式为STROKE或FILL_AND_STROKE时,设置笔刷的粗细度
* setXfermode(Xfermode xfermode);
设置图形重叠时的处理方式,如合并,取交集或并集,经常用来制作橡皮的擦除效果
2.文本绘制
* setFakeBoldText(boolean fakeBoldText);
模拟实现粗体文字,设置在小字体上效果会非常差
* setSubpixelText(boolean subpixelText);
设置该项为true,将有助于文本在LCD屏幕上的显示效果
* setTextAlign(Paint.Align align);
设置绘制文字的对齐方向
* setTextScaleX(float scaleX);
设置绘制文字x轴的缩放比例,可以实现文字的拉伸的效果
* setTextSize(float textSize);
设置绘制文字的字号大小
* setTextSkewX(float skewX);
设置斜体文字,skewX为倾斜弧度
* setTypeface(Typeface typeface);
设置Typeface对象,即字体风格,包括粗体,斜体以及衬线体,非衬线体等
* setUnderlineText(boolean underlineText);
设置带有下划线的文字效果
* setStrikeThruText(boolean strikeThruText);
设置带有删除线的效果
Canvas类介绍
当我们调整好画笔之后,现在需要绘制到画布上,这就得用Canvas类了。在android中既然把Canvas当做画布,那么就可以在画布上绘制我们想要的任何东西。除了在画布上绘制之外,还需要设置一些关于画布的属性,比如,画布的颜色、尺寸等。下面来分析Android中Canvas有哪些功能,Canvas提供了如下一些方法:
1. 设置属性
* Canvas(Bitmap bitmap): 以bitmap对象创建一个画布,则将内容都绘制在bitmap上,因此bitmap不得为null。
* Canvas(GL gl): 在绘制3D效果时使用,与OpenGL相关。
* isOpaque(boolean isOpaque):检测是否支持透明。
* setViewport(int left, int top, int right, int bottom, int clipflag): 设置画布中显示窗口。
* drawColor(int color): 设置Canvas的背景颜色。
* setBitmap(Bitmap mBitmap): 设置具体画布,画的内容,保存为一个Bitmap。
* clipRect(float left, float top, float right, float bottom): 设置显示区域,即设置裁剪区。
* translate(float x, float y): 平移画布。
* rotate(float degree, float px, float py): 旋转画布 。
* skew(float sx, float sy): 设置偏移量。
* save(): 将Canvas当前状态保存在堆栈,save之后可以调用Canvas的平移、旋转、错切、剪裁等操作。
* restore(): 恢复为之前堆栈保存的Canvas状态,防止save后对Canvas执行的操作对后续的绘制有影响。restore和save要配对使用,restore可以比save少,但不能比save多,否则会引发error。save和restore之间,往往夹杂的是对Canvas的特殊操作。
* save(int num):将Canvas当前状态保存在堆栈,并予以编号int
* restoreToCount(int num):恢复为之前堆栈保存的编号为int的Canvas状态
* concat(Matrix matrix):画布关联矩阵,画出来的内容按矩阵改变,而不是画布改变。
* Drawable.draw(Canvas canvas):将Drawable画到Canvas中
注:这种方式画Drawable怎么设置透明度呢?
((BitmapDrawable)Drawable).getPaint().setAlpha(mBgAlpha);
2. 画图
* canvas.drawPaint(Paint paint)
将画笔设置的颜色和透明度铺满画布
* drawRect(RectF rect, Paint paint)
绘制矩形,参数一为RectF一个区域
* drawRect(float left, float top, float right, float bottom, Paint paint)
绘制矩形,left:矩形left的x坐标,top:矩形top的y坐标,right:矩形right的x坐标,bottom:矩形bottom的y坐标
* drawRoundRect(RectF rect, float rx, float ry, Paint paint)
绘制圆角矩形, rx:x方向的圆角半径,ry:y方向的圆角半径
* drawRoundRect(float left, float top, float right, float bottom, float rx, float ry, Paint paint)
* drawPath(Path path, Paint paint)
绘制一个路径,参数一为Path路径对象
* drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint)
贴图,参数一就是我们常规的Bitmap对象,参数二是源区域(这里是bitmap),参数三是目标区域(应该在canvas的位置和大小),参数四是Paint画刷对象,因为用到了缩放和拉伸的可能,当原始Rect不等于目标Rect时性能将会有大幅损失。
* drawBitmap (Bitmap bitmap, float left, float top, Paint paint)
* drawLine(float startX, float startY, float stopX, float stopY, Paintpaint)
画线,参数一起始点的x轴位置,参数二起始点的y轴位置,参数三终点的x轴水平位置,参数四y轴垂直位置,最后一个参数为Paint 画刷对象。
* drawPoint(float x, float y, Paint paint)
画点,参数一水平x轴,参数二垂直y轴,第三个参数为Paint对象。
* drawText(String text, float x, floaty, Paint paint)
渲染文本,Canvas类除了上面的还可以描绘文字,参数一是String类型的文本,参数二文字左侧到x轴距离,参数三文字BaseLine到y轴距离,参数四是Paint对象。
* drawOval(RectF oval, Paint paint)
绘制椭圆,参数一是扫描区域,参数二为paint对象
* drawOval(float left, float top, float right, float bottom, Paint paint)
* drawCircle(float cx, float cy, float radius,Paint paint)
绘制圆,参数一是中心点的x轴,参数二是中心点的y轴,参数三是半径,参数四是paint对象;
* drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint)
画弧,参数一是RectF对象,指定圆弧的外轮廓矩形区域,参数二是起始角(度)在电弧的开始,参数三扫描角(度)开始顺时针测量的,参数四是如果这是真的话,包括椭圆中心的电弧,并关闭它,如果它是假这将是一个弧线,参数五是Paint对象;
Canvas对象的获取方式有两种:一种我们通过重写View.onDraw方法,View中的Canvas对象会被当做参数传递过来,我们操作这个Canvas,效果会直接反应在View中。
@Override
protected void onDraw(Canvas canvas) {
}
另一种就是当你想创建一个Canvas对象时使用的方法:
Bitmap b = Bitmap
.createBitmap(
100,
100, Bitmap
.Config.ARGB_8888)
Canvas c = new Canvas(b)
上面代码创建了一个尺寸是100*100的Bitmap,使用它作为Canvas操作的对象,这时候的Canvas就是使用创建的方式。当你使用创建的Canvas在bitmap上执行绘制方法后,你还可以将绘制的结果提交给另外一个Canvas,这样就可以达到两个Canvas协作完成的效果,简化逻辑。
从上面方法的名字看来我们可以知道Canvas可以绘制的对象有:弧线(arcs)、填充颜色(argb和color)、Bitmap、圆(circle和oval)、点(point)、线(line)、矩形(Rect)、图片(Picture)、圆角矩形(RoundRect)、文本(text)、顶点(Vertices)、路径(path)。下面我们就演示下canvas的一些简单用法:
绘制圆、椭圆
@Override
protected void onDraw(Canvas canvas) {
super
.onDraw(canvas)
Paint paint=new Paint()
paint
.setAntiAlias(true)
paint
.setColor(Color
.blue))
paint
.setStyle(Paint
.Style.FILL)
canvas
.drawCircle(
200,
200,
100,paint)
canvas
.drawOval(
500,
100,
800,
300, paint)
//上面代码等同于
//RectF rel=new RectF(
500,
100,
800,
300)
//canvas
.drawOval(rel, paint)
paint
.setStyle(Paint
.Style.STROKE)
paint
.setStrokeWidth(
20)
canvas
.drawCircle(
200,
500,
90,paint)
canvas
.drawOval(
500,
400,
800,
600, paint)
//上面代码等同于
//RectF rel2=new RectF(
500,
400,
800,
600)
//canvas
.drawOval(rel2, paint)
}
绘制矩形、圆角矩形
@Override
protected void onDraw(Canvas canvas) {
super
.onDraw(canvas)
Paint paint = new Paint()
paint
.setAntiAlias(true)
paint
.setColor(Color
.red))
paint
.setStyle(Paint
.Style.FILL)
canvas
.drawRect(
100,
100,
300,
300, paint)
canvas
.drawRoundRect(
400,
100,
600,
300,
30,
30, paint)
paint
.setStyle(Paint
.Style.STROKE)
paint
.setStrokeWidth(
20)
canvas
.drawRect(
100,
400,
300,
600, paint)
canvas
.drawRoundRect(
400,
400,
600,
600,
30,
30, paint)
}
绘制弧形、封闭弧形
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint =
new Paint();
paint.setAntiAlias(
true);
paint.setColor(Color.orange));
RectF rel =
new RectF(
100,
100,
300,
300);
canvas.drawArc(rel,
0,
270,
false, paint);
RectF rel2 =
new RectF(
100,
400,
300,
600);
canvas.drawArc(rel2,
0,
270,
true, paint);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(
20);
RectF rel3 =
new RectF(
100,
700,
300,
900);
canvas.drawArc(rel3,
0,
270,
false, paint);
RectF rel4 =
new RectF(
100,
1000,
300,
1200);
canvas.drawArc(rel4,
0,
270,
true, paint);
}
绘制文字
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint =
new Paint();
paint.setAntiAlias(
true);
paint.setColor(Color.orange));
paint.setTextSize(
100);
canvas.drawText(
"jEh",
80,
150, paint);
}
绘制图片
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint =
new Paint();
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.music);
canvas.drawBitmap(bitmap,
100,
100, mPaint);
}
绘制Path
通过Path这个类,我们可以画出三角形,梯形等多边形。 常用方法: moveTo();设置地点 lineTo();连接两点 close();连接起点和终点
Path
angle = new Path();
angle.moveTo(
250,
0);
angle.lineTo(
0,
500);
angle.lineTo(
500,
500);
angle.close();
canvas.drawPath(
angle, mPaint);
Canvas位置转换
通过组合这些对象我们可以画出一些简单有趣的界面出来,但是光有这些功能还是不够的,如果我要画一个仪表盘(数字围绕显示在一个圆圈中)呢? 幸好Android还提供了一些对Canvas位置转换的方法:rorate、scale、translate、skew(扭曲)等,而且它允许你通过获得它的转换矩阵对象(getMatrix方法) 直接操作它。这些操作就像是虽然你的笔还是原来的地方画,但是画纸旋转或者移动了,所以你画的东西的方位就产生变化。为了方便一些转换操作,Canvas 还提供了保存和回滚属性的方法(save和restore),比如你可以先保存目前画纸的位置(save),然后旋转90度,向下移动100像素后画一些图形,画完后调用restore方法返回到刚才保存的位置。
canvas.translate() - 画布的平移
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(Color.BLUE);
canvas.translate(
100,
100);
mPaint.setColor(Color.RED);
canvas.drawRect(
new Rect(
0,
0,
400,
400), mPaint);
}
canvas.scale( ) - 画布的缩放
关于scale,Android 提供了以下两个接口:
/**
* Preconcat the current matrix with the specified scale.
* @param sx The amount to scale in X
* @param sy The amount to scale in Y
*/
public native void scale(
float sx,
float sy);
/**
* Preconcat the current matrix with the specified scale.
* @param sx The amount to scale in X
* @param sy The amount to scale in Y
* @param px The x-coord for the pivot point (unchanged by the scale)
* @param py The y-coord for the pivot point (unchanged by the scale)
*/
public final void scale(
float sx,
float sy,
float px,
float py) {
translate(px, py);
scale(sx, sy);
translate(-px, -py);
}
@Override
protected void onDraw(Canvas canvas) {
super
.onDraw(canvas)
canvas
.drawColor(Color
.BLUE)
mPaint
.setColor(Color
.RED)
canvas
.drawRect(new Rect(
0,
0,
800,
800), mPaint)
// 保存画布状态
canvas
.save()
canvas
.scale(
0.5f,
0.5f)
mPaint
.setColor(Color
.YELLOW)
canvas
.drawRect(new Rect(
0,
0,
800,
800), mPaint)
// 画布状态回滚
canvas
.restore()
canvas
.scale(
0.5f,
0.5f,
400,
400)
mPaint
.setColor(Color
.GREEN)
canvas
.drawRect(new Rect(
0,
0,
800,
800), mPaint)
}
canvas.rotate( ) - 画布的旋转
canvas.rotate( )和canvas.scale()可以类比起来看,它也有两个可以使用的方法:
/**
* Preconcat the current matrix with the specified rotation.
* @param degrees The amount to rotate, in degrees
*/
public native void rotate(
float degrees);
/**
* Preconcat the current matrix with the specified rotation.
* @param degrees The amount to rotate, in degrees
* @param px The x-coord for the pivot point (unchanged by the rotation)
* @param py The y-coord for the pivot point (unchanged by the rotation)
*/
public final void rotate(
float degrees,
float px,
float py) {
translate(px, py);
rotate(degrees);
translate(-px, -py);
}
@Override
protected void onDraw(Canvas canvas) {
super
.onDraw(canvas)
canvas
.drawColor(Color
.BLUE)
mPaint
.setColor(Color
.RED)
canvas
.drawRect(new Rect(
0,
0,
800,
800), mPaint)
canvas
.save()
mPaint
.setColor(Color
.YELLOW)
canvas
.rotate(
45)
canvas
.drawRect(new Rect(
0,
0,
800,
800), mPaint)
canvas
.restore()
mPaint
.setColor(Color
.GREEN)
canvas
.rotate(
45,
400,
400)
canvas
.drawRect(new Rect(
0,
0,
800,
800), mPaint)
}
canvas.skew( ) - 画布的错切
public native void skew(float sx, float sy); 这个方法只要理解了两个参数即可: float sx:将画布在x方向上倾斜相应的角度,sx为倾斜角度的tan值; float sy:将画布在y轴方向上倾斜相应的角度,sy为倾斜角度的tan值; 注意,这里全是倾斜角度的tan值,比如我们打算在X轴方向上倾斜45度,tan45=1;
@Override
protected void onDraw(Canvas canvas) {
super
.onDraw(canvas)
canvas
.drawColor(Color
.BLUE)
mPaint
.setColor(Color
.RED)
canvas
.drawRect(new Rect(
0,
0,
400,
400), mPaint)
canvas
.save()
//
x方向上倾斜
45度
canvas
.skew(
1,
0)
mPaint
.setColor(Color
.YELLOW)
canvas
.drawRect(new Rect(
0,
0,
400,
400), mPaint)
canvas
.restore()
//
y方向上移动
400再倾斜
45度
canvas
.translate(
0,
400)
canvas
.skew(
0,
1)
mPaint
.setColor(Color
.GREEN)
canvas
.drawRect(new Rect(
0,
0,
400,
400), mPaint)
}
matrix的变换应用到canvas上
@Override
protected void onDraw(Canvas
canvas) {
super.onDraw(
canvas);
canvas.drawColor(Color.BLUE);
mPaint.setColor(Color.RED);
canvas.drawRect(
0,
0,
100,
100, mPaint);
canvas.save();
Matrix
matrix = new Matrix();
matrix.setScale(
2f,
2f);
canvas.concat(
matrix);
canvas.drawRect(
100,
100,
200,
200, mPaint);
canvas.restore();
canvas.drawRect(
400,
400,
500,
500, mPaint);
}
Matrix延伸: 我们通过animation来实现view组件的动画效果时候,实际上是改变canvas的matrix, matrix矩阵的作用主要是对每个坐标点(x,y)转换为另外的(x’,y’),必要的时候canvas还会通过clipRect()方法改变它的绘制可见范围,这样不至于做移动的时候看不到view组件。我们看到view的动画效果时,其实它的大小和布局都没有变化,所以会看到比较搞笑的现象,就是一个button通过translate偏离原来位置后,它的touch事件响应还是在原来位置上,而不是所看到的眼前位置。 Canvas的translate(int dx, int dy)方法,其实和通过设置它的matrix的postTranslate(int dx, int dy), preTranslate(int dx, int dy)方法效果是一样的, 唯独set系列的方法和pre, post的不同,它是直接设值,而后者它们是设置matrix的增量。 更进一步, 比如preTranslate, setTranslate, postTranslate这几个方法的调用顺序对坐标变换的影响。抽象的说pre方法是向前”生长”,从队列前面加入,post方法是向后”生长”,从队列后面加入,然后从前到后按顺序执行队列即可。具体拿个例子来说,比如一个matrix调用了下列一系列的方法: matrix.preScale(0.5f, 1); matrix.preTranslate(10, 0); matrix.postScale(0.7f, 1); matrix.postTranslate(15, 0); 则坐标变换经过的4个变换过程依次是:translate(10, 0) -> scale(0.5f, 1) -> scale(0.7f, 1) -> translate(15, 0), 所以对matrix方法的调用顺序是很重要的,不同的顺序往往会产生不同的变换效果。pre方法的调用顺序和post方法的互不影响,即以下的方法调用和前者在真实坐标变换顺序里是一致的, matrix.postScale(0.7f, 1); matrix.preScale(0.5f, 1); matrix.preTranslate(10, 0); matrix.postTranslate(15, 0);
而matrix的set方法则会对先前的pre和post操作进行刷除,而后再设置它的值,比如下列的方法调用: matrix.preScale(0.5f, 1); matrix.postTranslate(10, 0); matrix.setScale(1, 0.6f); matrix.postScale(0.7f, 1); matrix.preTranslate(15, 0); 其坐标变换顺序是translate(15, 0) -> scale(1, 0.6f) -> scale(0.7f, 1).
Canvas里scale, translate, rotate, concat方法都是pre方法,如果要进行更多的变换可以先从canvas获得matrix, 变换后再设置回canvas.