Android Canvas 说明

转载 2015年11月19日 14:42:19

Canvas 画布,用于在位图上进行绘制,内部关联一个mutable Bitmap, canvas在一系列操作后,展现在该Bitmap上。


什么时候有Canvas?

  1. 自定义view时, onDraw、dispatchDraw

  2. SurfaceHolder.lockCanvas();  操作SurfaceView时需要用到Canvas

  3. 自行创建。 

      Canvas c = new Canvas(bitmap);//要求参数bitmap为一个可变的Bitmap

     或 Canvas c = new Canvas(); c.setBitmap(b); 


API

canvas.drawPoint(100, 200, paint); //画像素点

canvas.drawPoints(new float[]{100,200, 100,220}, paint); //一组点 每两个元素表示x,y

canvas.drawLine(50, 200, 80, 300, paint); //直线两点x,y  x1,y1确定

canvas.drawLines(new float[]{50, 220, 100, 330, 115, 138, 459, 388}, paint); //一组直线

canvas.drawRect(rect, paint); //画矩形

canvas.drawRoundRect(new RectF(200, 10, 400, 80), 10, 80,paint);  //圆角矩形     10x方向圆角半径  80:y方向圆角半径

canvas.drawCircle(300, 700, 180, paint);  //圆形  圆心xy和半径值

canvas.drawArc(new RectF(100,700,400,1000), 180, 90,false,paint);//以矩形为边界,绘制弧形。顺时针绘制。0度在中心点到右水平线。true表示会连接到中心点,false不会连接,只会连接起始点和终点

canvas.drawOval(new RectF(100,700,200,900), p); //以矩形为边界,绘制椭圆。 如果矩形为正方形,那绘制的就是圆形

canvas.drawText(…) // 绘制文本

canvas.drawPath(path, p); //绘制出路径  路径内包含一些图形

canvas.drawTextOnPath(text, path, h, v, p); //沿着路径的图形绘制文本。h表示距离绘制的起点位置 v表示距离路径的位置。 当顺时针时v=0,文本紧贴图形外部;v<0离在图形外越来越远。逆时针时v=0,文本在图形内部;v>0文本离图形边越来越远

canvas.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG)); // 抗锯齿

canvas.drawBitmap(bmp, 0, 0, paint); 

canvas.drawBitmap(bmp, matrix, paint); 


多边形绘制

Path path = new Path();

path.moveTo(x, y); //起始点
path.lineTo(x, y); //到某点画直线
。。。
path.lineTo(x, y); 
path.close();

canvas.drawPath(path, paint);


位移、旋转、缩放、扭曲(倾斜)

canvas.translate(dx, dy);  位移  即将(0,0)原点移到 (dx,dy)    

canvas.rotate(float degrees); 默认以view的(0,0)原点 旋转

canvas.rotate(float degrees, float px, float py);

    内部会先translate(px,py); 再rotate(degrees);再translate(-px,-py);

    旋转后,x、y轴的指向也就改变了

canvas.scale(float sx, float sy); 以view的(0,0)为缩放中心

scale(float sx, float sy, float px, float py) ; 
       内部: translate(px, py);   
                   scale(sx, sy);  
                   translate(-px, -py);  这时平移的坐标相对于原来的坐标比例为: -px*sx, -py*sy

  1. paint.setColor(Color.BLACK);  
  2. canvas.drawLine(0,0,100,500,paint);  
  3.   
  4.         canvas.translate(5050);  
  5.         canvas.scale(0.5f,0.5f);  
  6.         paint.setColor(Color.BLUE);  
  7.         canvas.drawLine(0,0,100,500,paint);  
  8.   
  9.         canvas.translate(-50, -50);  
  10. //        canvas.scale(0.5f, 0.5f, 50, 50);  
  11.         paint.setColor(Color.CYAN);  
  12.         canvas.drawLine(0,0,100,500,paint);  

上例先绘制一条从(0,0)开始的  到 (100,500) 的 黑色线段;

  平移(50,50),xy缩小0.5倍。 这时绘制的起始点(0,0) 即是平移后的(50,50)这个位置, 结束点(100,500)即变为(50,250),蓝色线段;

  最后再平移(-50,-50),即只移动(-50*0.5,-50*0.5)=> (-25,-25), 以其为(0,0),绘制结束点为(50,250)的 青色线段

如下图:



canvas.skew(float sx, float sy);sx或sy为倾斜角度的tan值


save和restore

save就是保存当前的; restore 恢复、回退到上次save之前的状态。

     可以多次save,再restoreToCount(int count);回退到某次save后。

      int count = save(); 每save一次都返回一个count ;  或  int count = getSaveCount(); 

save();    Saves the current matrix and clip onto a private stack.   对应的flag:MATRIX_SAVE_FLAG | CLIP_SAVE_FLAG

saveLayer();  不含alpha;   图层需要一个矩形的限定区和paint画笔;  可以指定其它flag

saveLayerAlpha(); 含alpha;图层需要一个矩形的限定区和paint画笔; 可以指定其它flag.(保存成一个透明度为a的,大小为矩形r的图层)

  Canvas.MATRIX_SAVE_FLAG | Canvas.CLIP_SAVE_FLAG
            | Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.FULL_COLOR_LAYER_SAVE_FLAG
            | Canvas.CLIP_TO_LAYER_SAVE_FLAG;    //Canvas.ALL_SAVE_FLAG  含所有5种flag


clip

clipRect(rect,...);  

clipPath(path,...);  

clipRegion(...);  //已过时,类似操作推荐用 clipRect

canvas.save();
Region region = new Region();
region.set(new Rect(150, 0, 600, 700));
region.op(new Rect(0,0, 200, 300), Region.Op.UNION);
canvas.clipRegion(region); //裁剪范围
canvas.drawColor(Color.RED);//将bitmap绘制到相应的region
canvas.restore();

 public enum Op {
        DIFFERENCE(0), //区别上一个,即去掉上一个图形所占区域
        INTERSECT(1), //交集
        UNION(2),  //并集
        XOR(3),    //去掉交集的部份
        REVERSE_DIFFERENCE(4),  //反转,即区别下一个,即去掉当前图形所占区域
        REPLACE(5); //替换; 只保留当前图形
}


在执行了canvas的裁剪、平移、缩放、扭曲(skew)等操作,将影响其后执行的绘制draw的动作

所以一般在执行类似操作时 需要一对 save和restore


//----------------------------------------------------------------------------------------------------------------------------------------

这里学习hongyang(http://blog.csdn.net/lmj623565791/article/details/44098729)博客中的知识发现

public class ColorTrackView extends View {
	private int mTextStartX;
	private String mText = "编码编码";
	private Paint mPaint;
	private int mTextSize = 0;

	private int mTextOriginColor = 0xff000000;
	private int mTextChangeColor = 0xffff0000;

	private Rect mTextBound = new Rect();
	private int mTextWidth;
	private int mRealWidth;
	private float mProgress;

	public ColorTrackView(Context context) {
		super(context);
		init(context, null);
	}

	public ColorTrackView(Context context, AttributeSet attrs) {
		super(context, attrs);
		init(context, attrs);
	}

	public ColorTrackView(Context context, AttributeSet attrs, int defStyleAttr) {
		super(context, attrs, defStyleAttr);
		init(context, attrs);
	}

	private void init(Context context, AttributeSet attrs) {
		mTextSize = sp2px(getContext(), 30);

		mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);

		TypedArray ta = context.obtainStyledAttributes(attrs,
				R.styleable.ColorTrackView);
		mText = ta.getString(R.styleable.ColorTrackView_text);
		mTextSize = ta.getDimensionPixelSize(
				R.styleable.ColorTrackView_text_size, mTextSize);
		mTextOriginColor = ta.getColor(
				R.styleable.ColorTrackView_text_origin_color, mTextOriginColor);
		mTextChangeColor = ta.getColor(
				R.styleable.ColorTrackView_text_change_color, mTextChangeColor);
		mProgress = ta.getFloat(R.styleable.ColorTrackView_progress, 0);
		
		ta.recycle();

		mPaint.setTextSize(mTextSize);
		measureText();
	}

	private void measureText() {
		mTextWidth = (int) mPaint.measureText(mText);
		mPaint.getTextBounds(mText, 0, mText.length(), mTextBound);
	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		int width = measureWidth(widthMeasureSpec);
		int height = measureHeight(heightMeasureSpec);
		setMeasuredDimension(width, height);

		mRealWidth = getMeasuredWidth() - getPaddingLeft() - getPaddingRight();
		mTextStartX = mRealWidth / 2 - mTextWidth / 2;

	}

	private int measureHeight(int measureSpec) {
		int mode = MeasureSpec.getMode(measureSpec);
		int val = MeasureSpec.getSize(measureSpec);
		int result = 0;
		switch (mode) {
		case MeasureSpec.EXACTLY:
			result = val;
			break;
		case MeasureSpec.AT_MOST:
		case MeasureSpec.UNSPECIFIED:
			result = mTextBound.height();
			break;
		}
		result = mode == MeasureSpec.AT_MOST ? Math.min(result, val) : result;
		return result + getPaddingTop() + getPaddingBottom();
	}

	private int measureWidth(int measureSpec) {
		int mode = MeasureSpec.getMode(measureSpec);
		int val = MeasureSpec.getSize(measureSpec);
		int result = 0;
		switch (mode) {
		case MeasureSpec.EXACTLY:
			result = val;
			break;
		case MeasureSpec.AT_MOST:
		case MeasureSpec.UNSPECIFIED:
			// result = mTextBound.width();
			result = mTextWidth;
			break;
		}
		result = mode == MeasureSpec.AT_MOST ? Math.min(result, val) : result;
		return result + getPaddingLeft() + getPaddingRight();
	}

	@Override
	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);
		drawText(canvas, mTextChangeColor, mTextStartX,
				(int) (mTextStartX + mProgress * mTextWidth));
		drawText(canvas, mTextOriginColor, (int) (mTextStartX + mProgress
				* mTextWidth), mTextStartX + mTextWidth);
	}

	private void drawText(Canvas canvas, int color, int startX, int endX) {
		mPaint.setColor(color);
		// canvas.save(Canvas.CLIP_SAVE_FLAG);
		canvas.clipRect(startX, 0, endX, getMeasuredHeight());
		canvas.drawText(mText, mTextStartX, getMeasuredHeight() / 2
				+ mTextBound.height() / 2, mPaint);
		// canvas.restore();
	}

	public static int sp2px(Context context, float spValue) {
		return (int) (spValue
				* context.getResources().getDisplayMetrics().scaledDensity + 0.5f);
	}

	public float getProgress() {
		return mProgress;
	}

	public void setProgress(float progress) {
		this.mProgress = progress;
		invalidate();
	}
}


当这里的drawText()方法里面的注释掉之后,发现文字显示不了。

在执行了canvas的裁剪、平移、缩放、扭曲(skew)等操作,将影响其后执行的绘制draw的动作

所以一般在执行类似操作时 需要一对 save和restore

就明白了上面的含义了。


public class ColorTrackActivity extends Activity {
	private MyHandler handler = new MyHandler();
	private ColorTrackView text;
	private int progress = 0;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.color_track_activity);
		text = (ColorTrackView) findViewById(R.id.text);
	}
	
	public void start(View v) {
//		ObjectAnimator.ofFloat(text, "progress", 0, 1).setDuration(2000)  
//        .start();  
		handler.postDelayed(new Runnable() {
			
			@Override
			public void run() {
				if (progress > 100) {
					return;
				}
				handler.sendEmptyMessage(0);
			}
		}, 20);
	}
	
	class MyHandler extends Handler {
		@Override
		public void handleMessage(Message msg) {
			text.setProgress((progress++) / 100f);
			start(text);
		}
	}
}
可以看到这里hongyang使用的是属性动画,而我这里直接handler实现。

总结:快速的学习人家的博客的时候,需要注意几点。

(1)明白原理,去除代码中多余的部分,便于理解;

(2)看到不明白的知识点不要放过,比如这里,canvas的操作,使用注释的方法去掉就可以看到有啥影响了。

(3)自己想办法看看有啥其他的方法实现的,提高自己。

图形绘制之——Canvas详解(四)-Bitmap(位图)及Matrix矩阵

前面我们提到过canvas相当于画家,而bitmap相当于画布,前面博客的例子都是直接利用canvas绘制,这里我们来学习一下,利用bitmap先将图形绘制好,然后一起放到最终的canvas中^^。 ...
  • womengmengyan
  • womengmengyan
  • 2015年09月17日 12:00
  • 6317

android canvas常用的方法解析(一)

android canvas常用的方法解析
  • coderinchina
  • coderinchina
  • 2016年05月18日 19:07
  • 5339

android 里面Canvas绘制文本的方法

在做项目的时候总是会遇到一些要再图片上叠加文字的需求,这个问题的解决方式有很多种,通过布局来实现:一个ImageView和一个TextView堆放好就行,或者直接用button,background为...
  • ddq1234567
  • ddq1234567
  • 2015年09月02日 00:01
  • 1151

android canvas 绘制bitmap并保存到本地

自定义一个view,重载draw方法(不是重载ondraw,不然图片保存下来是空白的。)...
  • cece0926
  • cece0926
  • 2014年10月14日 11:14
  • 16448

Android中Canvas绘图基础详解(附源码下载)

Android中,如果我们想绘制复杂的自定义View或游戏,我们就需要熟悉绘图API。Android通过Canvas类暴露了很多drawXXX方法,我们可以通过这些方法绘制各种各样的图形。Canvas...
  • sunqunsunqun
  • sunqunsunqun
  • 2015年11月11日 00:30
  • 30007

Android Canvas绘图详解(图文)

http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2012/1212/703.html Android中使用图形处理引擎...
  • yunnywu
  • yunnywu
  • 2015年09月28日 14:28
  • 2757

Android Canvas练习(1)画一张报表来玩

昨天翻了翻Android的Canvas函数,发现这玩意和以前用VC时,用的API差不多搞法,以前做数据库方面的系统时,都是直接用API画的报表, 现在用Android来再试试手看看,感受感受,弄了下,...
  • xcltapestry
  • xcltapestry
  • 2014年04月06日 11:14
  • 5546

Android实战技巧之二十九:画布Canvas

Android Framework提供了一些2D画图的API,android.graphics包就是其中之一。 为了画一些东西,需要4个元素(或称组件)协同来完成: * 位图:Bitmap来保持(...
  • lincyang
  • lincyang
  • 2015年05月07日 13:29
  • 14269

Android 中通过Canvas 与线程结合实现动画效果

前段时间在公司做了一个模块,不使用第三方动画效果类,直接通过Canvas 进行图像的绘制,并通过Thread实现动画的效果 该模块主要是实现车辆运行时候的道路运行效果,在进行实施前做了一个相关的Dem...
  • Adrian24
  • Adrian24
  • 2016年06月09日 23:23
  • 4030

Android Canvas 画各种图形和Bitmap详解

Android中,如果我们想绘制复杂的自定义View或游戏,我们就需要熟悉绘图API。Android通过Canvas类暴露了很多drawXXX方法,我们可以通过这些方法绘制各种各样的图形。Canvas...
  • watertekhqx
  • watertekhqx
  • 2016年07月26日 17:47
  • 2508
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Android Canvas 说明
举报原因:
原因补充:

(最多只允许输入30个字)