Android利用Canvas和Paint实现画图和自定义布局组件

本文详细介绍了Android中2D绘图的基本概念与常用API,包括Canvas与Paint的使用方法,并通过两个实例展示了如何利用自定义View组件及SurfaceView进行图形绘制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

       实例源码下载地址 :http://download.csdn.net/detail/xiaocaoxiekun/7809389

     Android中使用图形处理引擎,2D部分是android SDK内部自己提供。使用该引擎中的API我们可以实现常用的2D图像的绘制,以及一些自定义UI组件的构造,比如自己定义指针式时钟。

    1. 常用绘图API简介:

       Android 2D 图形处理引擎常用到的API主要位于android.graphics.drawable包下面,下面就对一些常用的API进行介绍:

       Canvas 是图形编程中一个很常用的概念,无论实在静态页面HTML中还是在动态网页,直到现在的移动开发中都可以看见Canvas的身影。Canvas 常被称为画布,它是图形绘制的执行者,它统帅着所有的机型图形绘制的API,其提供了draw*方法来实现位图的设计。

        drawRect(RectF rect, Paint paint) //绘制区域,参数一为RectF一个区域

        drawPath(Path path, Paint paint) //绘制一个路径,参数一为Path路径对象

        drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint)  //贴图,参数一就是我们常规的Bitmap对象,参数二是源区域(这里是bitmap),参数三是目标区域(应该在canvas的位置和大小),参数四是Paint画刷对象,因为用到了缩放和拉伸的可能,当原始Rect不等于目标Rect时性能将会有大幅损失。

        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轴,参数三y轴,参数四是Paint对象。

        drawOval(RectF oval, Paint 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对象;

       drawText(String text, float x, float y, Paint paint)  //渲染文本

        由Canvas提供的方法可以看出,在绘图过程中都离不开Paint对象,那么Paint究竟代表着什么呢?下面就来介绍一下Paint:

         Paint 被称为画笔,刷子等。主要是制定如何将基本图形绘制到位图上,相当于是规则制作者, 用来规定画布上的字体样式, 画布背景,对齐方式等,Paint 常用的API如下:

         Shader setShader(Shader shader) //设置阴影,Shader类是一个矩阵对象,如果为NULL将清除阴影

         setARGB(int a, int r, int g, int b) // 设置 Paint对象颜色,参数一为alpha透明值

         setAlpha(int a) // 设置alpha不透明度,范围为0~255

         setColor(int color)  // 设置颜色

         setTextSize(float textSize)  // 设置字体大小

         setUnderlineText(booleanunderlineText)  // 设置下划线

         setTextAlign(Align.CENTER)  // 设置文本的对齐方式

         注:如果设置了画笔Paint的对齐属性,那么在进行文本渲染的时候,drawText(String text, float x, float y, Paint paint)  中设置的X坐标可能不是我们想要的结果:在设置了setTextAlign(Align.CENTER)的时候,X坐标实际上是Text文本中间点的坐标,而不是文本起始位置的坐标。

    2. 怎么样绘制一个图形:

           android为我们提供了绘制图形的工具,那我们究竟需要将这些图形绘制在哪些地方呢?当画图形时,典型情况下,你将使用以下两方法之一:

  • A.把你的图形或动画绘制到你的Layout中的一个View上.你的图形的绘制被系统的标准绘制过程所处理—你只需定义进人View的图形即可.

  • B.在一个Canvas中直接绘制图形.用此方法,你需亲自调用恰当的类的onDraw()方法(把它传给你的Canvas),或Canvas的draw...()方法们中的一个(比如drawPicture()).在这样做时,你也可以任意控制动画

 在这里我们主要学习的是利用Canvas直接进行图形的绘制,对于动作和视频类游戏,需要经常对图形进行重绘时,采用这种方法,这种绘制方法,Android也为开发人员提供了最终可供选择的开发方案:

 在UIActivity线程(UI主线程)中,自定义View组件(只需要集成View即可),然后调用invalidate()然后处理onDraw()回调,在onDraw()中调用canvas的draw...()方法来绘制自己想要的图形。

 在异步线程中,通过管理SurfaceView 快速的向主线程的Canvas中传递绘画的动作。

 下面我们通过实例来讲解2中绘制方法的用法,顺便熟悉一下绘图API的使用:

  (1):通过自定义View组件,将图形绘制在主线程中,我们只需要实现View的onDraw方法即可:

	 public DrawView(Context mContext) {  
	    super(mContext);  
	    setBackgroundColor(Color.BLACK);  
	    
	    //绘制画笔
	    mPaint=new Paint();
	    mPaint.setColor(Color.WHITE); //设置画笔的颜色,即图形的边框(包含字体)
	    mPaint.setStrokeWidth(5); //设置画笔的大小,相当于图形的边框宽度
	    mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
	    mPaint.setAntiAlias(true);//不抗锯齿
	    mPaint.setTextAlign(Align.CENTER);
	    mPaint.setTextSize(24);
	 }  
	  
	 @Override 
	    protected void onDraw(Canvas mCanvas){  
	        super.onDraw(mCanvas);  
	        mCanvas.drawRect(10, 30, 150,200, mPaint);
	        
	        mPaint.setColor(Color.RED);
	        mPaint.setStrokeWidth(2);
	        mCanvas.drawText("draw Text", 150, 150, mPaint);
	        
	        mPaint.setStyle(Paint.Style.STROKE);
	        mPaint.setColor(Color.BLUE);
	        mPaint.setAntiAlias(true);//抗锯齿
	        mCanvas.drawRect(150, 40, 290,200, mPaint);
	    }

(2) 通过surfaceView ,在非主线程中绘制图形,可以避免画图任务繁重的时候造成主线程阻塞,从而提高了程序的反应速度。在游戏开发中多用到SurfaceView,游戏中的背景、人物、动画等等尽量在画布canvas中画出。

      SurfaceView是View的子类,它内嵌了一个专门用于绘制的Surface。如果我们需要创建一个SurfaceView对象,我们需要按照一下步骤进行:

      SurfaceView的使用首先继承SurfaceView,并实现SurfaceHolder.Callback接口,实现它的三个方法:surfaceCreated,surfaceChanged,surfaceDestroyed。
      surfaceCreated(SurfaceHolder holder):surface创建的时候调用,一般在该方法中启动绘图的线程。
      surfaceChanged(SurfaceHolder holder, int format, int width,int height):surface尺寸发生改变的时候调用,如横竖屏切换。
      surfaceDestroyed(SurfaceHolder holder) :surface被销毁的时候调用,如退出游戏画面,一般在该方法中停止绘图线程。
      还需要获得SurfaceHolder,并添加回调函数,这样这三个方法才会执行。

    

public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback{
	private SurfaceHolder mSurfaceHolder;
	private SurfaceThread mSurfaceThread;
	
	public MySurfaceView(Context context) {
		super(context);
		mSurfaceHolder=this.getHolder();
		mSurfaceHolder.addCallback(this);
		mSurfaceThread=new SurfaceThread(mSurfaceHolder);
	}

	public MySurfaceView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
	}

	public MySurfaceView(Context context, AttributeSet attrs) {
		super(context, attrs);

	}

	//在surface的大小发生改变时激发
	@Override
	public void surfaceChanged(SurfaceHolder holder, int format, int width,
			int height) {
		
	}
     
	//在创建时激发,一般在这里调用画图的线程
	@Override
	public void surfaceCreated(SurfaceHolder holder) {
		mSurfaceThread.isrun=true;
		mSurfaceThread.start();
	}

	//销毁时激发,一般在这里将画图的线程停止、释放
	@Override
	public void surfaceDestroyed(SurfaceHolder holder) {
		mSurfaceThread.isrun=false;
	}
	
	//创建一个线程,对surface 进行业务处理
	class SurfaceThread extends Thread{
		private SurfaceHolder mHolder;
		public boolean isrun;
		public SurfaceThread(SurfaceHolder mHolder){
			this.mHolder=mHolder;
			isrun=true;
		}
		
		@Override
		public void run(){
			int count = 0;
			while(isrun){       
				Canvas c = null;    
				try {
					synchronized (mHolder){     
						c = mHolder.lockCanvas();//锁定画布,一般在锁定后就可以通过其返回的画布对象Canvas,在其上面画图等操作了。                   
						c.drawColor(Color.BLACK);//设置画布背景颜色             
					    Paint p = new Paint(); //创建画笔        
					    p.setColor(Color.WHITE);        
					    Rect r = new Rect(100, 50, 300, 250);           
					    c.drawRect(r, p);           
					    c.drawText("这是第"+(count++)+"秒", 100, 310, p);
					}
				}
                catch (Exception e) {
               	      e.printStackTrace();  
                }
                finally{
                    if(c!= null){
                    	mHolder.unlockCanvasAndPost(c); //结束锁定画图,并提交改变。
                    }
                }
		    }
	   }
	}
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值