好记性不如烂笔头,记录一下canvas常见的方法及效果演示
Canvas多使用在自定义View中,onDraw()方法绘制图形
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
}
canvas 可以大致分为一下几类:
- drawXXX 等一系列绘制方法
- scale rotate clip 等对画布进行操作
- save restore 回滚相关方法
drawText()/drawBitmap()
String text = "MillerJK";
Paint mBluePaint = new Paint();
mBluePaint.setColor(Color.BLUE);
mBluePaint.setTextSize(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, 40, getResources().getDisplayMetrics()));// **setTextSize() and setStrokeWidth() need px here**
canvas.drawText(text, 200, 200, mBluePaint);
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.aa);
canvas.drawBitmap(bitmap, 200, 200, mBluePaint);
Paint paint = new Paint();
paint.setColor(Color.RED);
paint.setStrokeWidth(10);
canvas.drawPoint(200, 200, paint);
效果图:
(妹子好漂亮!)
从图中可见文字在坐标(200,200)的右上角,而图片则是在右下角,如果想让TEXT文本 图片 以(200,200)为中心 ,可参考如下代码
Rect rect = new Rect();
mBluePaint.getTextBounds(text, 0, text.length(), rect);
canvas.drawText(text, 300 - rect.width() / 2, 300 + rect.height() / 2, mBluePaint);
canvas.drawBitmap(bitmap, 200 - bitmap.getWidth() / 2, 200 - bitmap.getHeight() / 2, mBluePaint);
将文字的信息记录在Rect中,通过该类提供的api我们可以通过width() , height(),left,top 等,android 里还有RectF类,Rect传递参数为int类型,而RecF传递参数为float类型,相对来说保存的信息更加精确。
drawRect()/drawArc()/drawOval()/drawLine()
Paint paint = new Paint();
paint.setStyle(Paint.Style.STROKE);
paint.setColor(Color.RED);
canvas.drawRect(new RectF(400, 100, 600, 200), mPaint);
canvas.drawArc(new RectF(650, 100, 750, 200), 0, 90, false, mPaint);//true 弧线和圆心组成的区域 false只显示弧线 圆心则是矩形的中心
Rect rect = new Rect(100, 100, 300, 250);
canvas.drawOval(new RectF(rect), mPaint); //绘制内切圆
canvas.drawLine(100, 300, 300, 300, mPaint);//绘制直线
效果图:
SweepGradient
SweepGradient mSweepGradient = new SweepGradient(240, 360, new int[]{Color.WHITE, Color.BLACK}, new float[]{0.5f, 1f});
mPaint = new Paint();
mPaint.setStyle(Paint.Style.FILL);
mPaint.setShader(mSweepGradient);
canvas.drawCircle(240, 360, 200, mPaint);
效果如下:
其中colors至少两种 , postions 可以为null,需要注意一旦postions不为null,需保证colors和postions 数组length()必须相同,否则会报错:
java.lang.IllegalArgumentException: color and position arrays must be of equal length
从这个例子也可以很容易看出,扫描是从右边开始向下顺时针扫的,White 所占的区域为0-0.5 黑色所占的区域为0.5-1 。
Path
lineTo()
Paint paint = new Paint();
paint.setColor(Color.RED);
paint.setStyle(Paint.Style.STROKE);
mPath.lineTo(100, 100);
mPath.lineTo(100, 200);
mPath.lineTo(150, 250);
canvas.drawPath(mPath, paint);
效果图如下:
默认情况下Path的起始点是屏幕的左上角(0,0),如果不想起始点为(0,0)的话就使用moveTo(x,y)方法,如果想让终止点和起始点封闭需使用close()方法, 比如以上代码,在lineTo(100,100)之前添加 mPath.moveTo(50,50),在lineTo(150,250)之后添加 mPath.close() ,则效果如下:
addArc() arcTo()
Path path = new Path();
Paint paint = new Paint();
paint.setColor(Color.RED);
paint.setStyle(Paint.Style.STROKE);
RectF rectF = new RectF(200, 200, 400, 400);
path.moveTo(50, 50);
path.arcTo(rectF, 0, 90);
path.addArc(new RectF(rectF), -90, -150);
canvas.drawPath(path, paint);
效果如下:
addArc可以直接加入一段椭圆弧。使用arcTo还需要使用moveTo指定当前点的坐标。arcTo如果当前点坐标和曲线的起始点不是同一个点的话,还会自动添加一条直线补齐路径。
quadTo()
mPath.moveTo(20, 50);
mPath.lineTo(100, 100);
mPath.quadTo(100, 200, 150, 250); //二阶贝塞尔曲线 三阶贝塞尔曲线:cubicTo()
canvas.drawPath(mPath, mPaint);
效果如下:
二阶贝塞尔 三阶贝塞尔 曲线 此处不在说些什么。参考:
translate()
Paint paint = new Paint();
paint.setColor(Color.RED);
paint.setStrokeWidth(20);
canvas.translate(200, 200);
canvas.drawPoint(0,0,paint);
paint.setColor(Color.BLUE);
canvas.translate(100,100);
canvas.drawPoint(0,0,paint);
效果如下:
Note
画布先以(200,200)为原点,然后执行translate(100,100) ,在200 的基础上有向右下各移动 100,如不理解可参考:http://blog.csdn.net/harvic880925/article/details/39080931
rotate()
Paint paint = new Paint();
paint.setColor(Color.RED);
Rect rect = new Rect(300,10,500,100);
canvas.drawRect(rect,paint);
paint.setColor(Color.BLUE);
canvas.rotate(30);
canvas.drawRect(rect,paint);
paint.setColor(Color.DKGRAY);
Rect rect1 = new Rect(550,10,700,100);
canvas.drawRect(rect1,paint);
效果图如下:
这个例子几乎是参照 http://blog.csdn.net/harvic880925/article/details/39080931 写的,参照这篇博客的rotate方法,这里我有多画了一个矩形,主要是为了说明两点:
1、每次调用canvas.drawXXXX系列函数来绘图进,都会产生一个全新的Canvas画布。
2、如果在DrawXXX前,调用平移、旋转等函数来对Canvas进行了操作,那么这个操作是不可逆的!每次产生的画布的最新位置都是这些操作后的位置。(关于Save()、Restore()的画布可逆问题的后面再讲)
scale()
Paint paint = new Paint();
paint.setStyle(Paint.Style.STROKE);
canvas.drawRect(new Rect(10, 10, 400, 400), paint);
paint.setColor(Color.BLUE);
canvas.scale(0.5f, 0.5f,205,205);
canvas.drawRect(new Rect(10, 10, 400, 400), paint);
效果图:
scale 包括两种方法,区别在于设置缩放中心。
scale(sx, sy, px, py) 的源码如下:
public final void scale(float sx, float sy, float px, float py) {
translate(px, py);
scale(sx, sy);
translate(-px, -py);
}
最开始看到这段源码的时候,有些疑惑。总感觉上述代码实现的效果应该如下:
(wrong)
但是源码就是源码是不会错误的啊!那应该怎么理解?
其实上面在rotate() 我验证那两点总结,你只要是在认真的看一看,然后结合这个scale()源码想一想,自然就会明白了。
关于Canvas 就先写到这 ,至于 restore save 找时间在写一篇总结!这两个方法作用也是想当的大。