Paint类介绍
Paint即画笔,在绘图过程中起到了极其重要的作用,画笔主要保存了颜色, 样式等绘制信息,指定了如何绘制文本和图形,画笔对象有很多设置方法,大体上可以分为两类,一类与图形绘制相关,一类与文本绘制相关。
Canvas类介绍
当我们调整好画笔之后,现在需要绘制到画布上,这就得用Canvas类了。在android中既然把Canvas当做画布,那么就可以在画布上绘制我们想要的任何东西。除了在画布上绘制之外,还需要设置一些关于画布的属性,比如,画布的颜色、尺寸等。下面来分析Android中Canvas有哪些功能,Canvas提供了如下一些方法:
设置属性
画图
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);
//设置空心Style
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);
//上面代码等同于
//Rect mSrc = new Rect(0, 0, mBitWidth, mBitHeight);
//Rect mDest = new Rect(100,100,100+mBitWidth,100+mBitHeight);
//canvas.drawBitmap(bitmap, mSrc, mDest, 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);
通过组合这些对象我们可以画出一些简单有趣的界面出来,但是光有这些功能还是不够的,如果我要画一个仪表盘(数字围绕显示在一个圆圈中)呢? 幸好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.
原文:http://blog.csdn.net/huaxun66/article/details/52222643