Android Canvas画图

画在bitmap上可以这么设置canvas

Bitmap b = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(b);

画在View上 (On a View)

如果你的应用不许需要大量处理帧,也不需要高的帧处理速率,比如下棋游戏,蛇吃豆游戏,动画都比较慢的这类。考虑创建一个View,然后在 View.onDraw()中用canvas画图。这样android框架会给你提供一个预先定义的Canvas,代替你自己来调用画图函数。 Android框架有必要的时候才会调用onDraw函数,每次你的应用准备要画图的时候,让那个View调用 invalidate(),然后android框架会调用onDraw函数,但不保证立刻调用。

Note: 从线程中调用 invalidate,而不是在Main Activity的线程中调用,必须要调用postInvalidate().

 

1、继承View的class

public final class LyricView extends View {
	public LyricView(Context context) {
		super(context);
	}

	/**
	 * 重绘视图
	 */
	@Override
	protected void onDraw(Canvas c) {
		super.onDraw(c);
		
		Paint pText = new Paint(); //画笔
		pText.setColor(Color.GRAY);
		pText.setTextSize(10);
		pText.setAntiAlias(true); //消除锯齿
		c.drawText("my draw!", 0, 0, pText);		
	  //画图片 
    Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);  
    c.drawBitmap(bitmap, 250,360, p);
	}
}


2、在界面的xml中添加一个layoutView,用来放置画图的LyricView

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >
    <LinearLayout
        android:id="@+id/lyoutView"
        android:layout_width="fill_parent"
        android:orientation="vertical" 
        android:layout_height="150dp"
        android:layout_weight="2" >
</LinearLayout> 
</LinearLayout>


3、在Activity中

public class Mp3PlayerActivity extends Activity {
	@Override
	protected void onCreate(Bundle savedInstanceState) {

		super.onCreate(savedInstanceState);
		setContentView(R.layout.mp3player);

		
		// 用LinearLayout存放画图的View
		LinearLayout layout = (LinearLayout) findViewById(R.id.lyoutView);
		vwLrc = new LyricView(layout.getContext());
		layout.addView(vwLrc);
		}
}




On a SurfaceView 用surfaceView画图

SurfaceView是View的子类,提供了画图的surface。目的是为了给应用的第二个线程提供画图surface,这样就不需要等待系统的View准备好画图,相反,引用了SurfaceView的第二个线程可以按自己的节奏画图。

开始使用surfaceview,创建一个继承SurfaceView的类,这个类也必须implement SurfaceHolder.Callback 通过SurfaceHolder来处理surface对象,当你的surfaceView初始化的时候,通过getHolder()获取SurfaceHolder ,然后再调用addCallback() 把surfaceHolder传递给它,然后重载你surfaceView类的surfaceHolder.Callback的所有方法。 为了在你第二个线程中使用canvas,你必须传递线程到你的SurfaceHolder,通过lockCanvas()获取Canvas,然后你就可以用Canvas来画图了,用完之后,调用unlockCanvasAndPost()并传递Canvas对象参数。

http://blog.csdn.net/kongbaidepao/article/details/15028099

surfaceView 继承于 View,View里面嵌套了一个专门用于画图的 surface, 对于一个View的onDraw()方法,不能够满足将其移动到后台线程中去。因为从后台线程修改一个GUI元素会被显式地禁止的。

当需要快速地更新View的UI,或者当前渲染代码阻塞GUI线程的时间过长的时候,SurfaceView就是解决上述问题的最佳选择。SurfaceView封装了一个Surface对象,而不是Canvas。这一点很重要,因为Surface可以使用后台线程绘制。对于那些资源敏感的操作,或者那些要求快速更新或者高速帧率的地方,例如使用3D图形,创建游戏,或者实时预览摄像头,这一点特别有用。 可以直接从内存或硬件设备比如相机等取得图像数据,是个非常重要的绘图容器。它的特性是:可以在主线程之外的线程中向屏幕绘图。这样可以避免画图任务繁重的时候造成主线程阻塞,从而提高了程序的反应速度。绘制的东西直接复制到显存从而显示出来,这使得显示速度会非常快,而在Surface 被销毁之前必须结束。

下面给个简单的例子,就是不停的绘制 ,这样按照前面说的,就可以再 上面绘制各种自己想要的效果了:

 

1、layout.activity_draw .xml中添加surfaceView控件

 

2、Activity中代码:

public class SurfaceDraw  extends Activity{  
    private SurfaceView    sf;      
    private SurfaceHolder  sfh;   //surfaceView的 控制器  
     
   @Override  
   protected void onCreate(Bundle savedInstanceState) {  
       // TODO Auto-generated method stub  
       super.onCreate(savedInstanceState);  
       setContentView(R.layout.activity_draw);  
       sf = (SurfaceView) this.findViewById(R.id.SurfaceView01);  
       //得到控制器  
       sfh = sf.getHolder();  
       //对 surfaceView 进行操作  
       sfh.addCallback(new DoThings());// 自动运行surfaceCreated以及surfaceChanged  
   }  
     
     
   private class DoThings implements SurfaceHolder.Callback{  
       @Override  
       public void surfaceChanged(SurfaceHolder holder, int format, int width,  
               int height) {  
           //在surface的大小发生改变时激发  
           System.out.println("surfaceChanged");  
       }  
 
       @Override  
       public void surfaceCreated(SurfaceHolder holder){  
           new Thread(){  
               public void run() {  
                   while(true){  
                       //1.这里就是核心了, 得到画布 ,然后在你的画布上画出要显示的内容  
                       Canvas c = sfh.lockCanvas(new Rect(0, 0, 200, 200));  
                       //2.开画  
                       Paint  p =new Paint();  
                       p.setColor(Color.rgb( (int)(Math.random() * 255),   
                               (int)(Math.random() * 255) ,  (int)(Math.random() * 255)));  
                       Rect aa  =  new Rect( (int)(Math.random() * 100) ,  
                               (int)(Math.random() * 100)   
                               ,(int)(Math.random() * 500)   
                               ,(int)(Math.random() * 500) );  
                       c.drawRect(aa, p);  
                       //3. 解锁画布   更新提交屏幕显示内容  
                       sfh.unlockCanvasAndPost(c);  
                       try {  
                           Thread.sleep(1000);  
                             
                       } catch (Exception e) {  
                       }  
                   }  
               };  
           }.start();  
             
       }  
 
       @Override  
       public void surfaceDestroyed(SurfaceHolder holder) {  
              //销毁时激发,一般在这里将画图的线程停止、释放。线程运行结束后,就死亡了。
              //这个例子是不停地画方块。如果线程死亡了,又调用thread.destroy等,
              //会出现java.lang.UnsupportedOperationException这种错误  
           System.out.println("surfaceDestroyed==");     
       }     
   }  
}  


 

Note: On each pass you retrieve the Canvas from the SurfaceHolder, the previous state of the Canvas will be retained. In order to properly animate your graphics, you must re-paint the entire surface. For example, you can clear the previous state of the Canvas by filling in a color with drawColor() or setting a background image with drawBitmap(). Otherwise, you will see traces of the drawings you previously performed.

画新图的时候,上次画得图还会保留,如果不想保留上次的画图,通过Canvas的drawColor()或者DrawBitmap()就可以清空上次的状态,重新画整个surface。

 

上面的方式使用了控件,不用surfaceview控件,直接按照官方说明进行画图,如下:

代码来自这里


1、      创建一个绘制线程如下

//绘制线程  
public class MyThread extends Thread  
{  
      private SurfaceHolder holder;  
      private boolean run;  
       
      public  MyThread(SurfaceHolder holder)  
      {  
                this.holder = holder;  
                run = true;  
      }  

      @Override  
      public void run()  
      {  
                int counter = 0;  
                Canvas canvas = null;  
                while(run)  
                {  
                         // 具体绘制工作  
                         try  
                         {  
                                  // 获取Canvas对象,并锁定之  
                                  canvas= holder.lockCanvas();  
                                   
                                  // 设定Canvas对象的背景颜色  
                                  canvas.drawColor(Color.WHITE);  
                                   
                                  // 创建画笔  
                                  Paint p = new Paint();  
                                  // 设置画笔颜色  
                                  p.setColor(Color.BLACK);  
                                  // 设置文字大小  
                                  p.setTextSize(30);  
                                   
                                  // 创建一个Rect对象rect  
                                  Rect  rect = new Rect(100, 50, 380, 330);  
                                  // 在canvas上绘制rect  
                                  canvas.drawRect(rect,p);  
                                  // 在canvas上显示时间  
                                  canvas.drawText("Interval = " + (counter++) + " seconds.", 100, 410, p);  
                                  Thread.sleep(1000);  
                         }  
                         catch(Exception e)  
                         {  
                                  e.printStackTrace();  
                         }  
                         finally  
                         {  
                                  if(canvas != null)  
                                  {  
                                            // 解除锁定,并提交修改内容  
                                            holder.unlockCanvasAndPost(canvas);  
                                  }  
                         }  
                }  
      }  

      public boolean isRun()  
      {  
                return run;  
      }  
       
      public void setRun(boolean run)  
      {  
                this.run = run;  
      }  
}  


2、      自定义一个SurfaceView类如下:

public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback  
{  
         private SurfaceHolder holder;  
         private MyThread myThread;  
          
         public  MySurfaceView(Context context)  
         {  
                   super(context);  
                    
                   // 通过SurfaceView获得SurfaceHolder对象  
                   holder = getHolder();  
                    
                   // 为holder添加回调结构SurfaceHolder.Callback  
                   holder.addCallback(this);  
                    
                   // 创建一个绘制线程,将holder对象作为参数传入,这样在绘制线程中就可以获得holder  
                   // 对象,进而在绘制线程中可以通过holder对象获得Canvas对象,并在Canvas上进行绘制  
                   myThread = new MyThread(holder);  
         }  
  
         // 实现SurfaceHolder.Callback接口中的三个方法,都是在主线程中调用,而不是在绘制线程中调用的  
         @Override  
         public void  surfaceChanged(SurfaceHolder holder, int format, int width, int height)  
         {  
         }  
  
         @Override  
         public void  surfaceCreated(SurfaceHolder holder)  
         {  
                   // 启动线程。当这个方法调用时,说明Surface已经有效了  
                   myThread.setRun(true);  
                   myThread.start();  
         }  
  
         @Override  
         public void surfaceDestroyed(SurfaceHolder holder)  
         {  
                   // 结束线程。当这个方法调用时,说明Surface即将要被销毁了  
                   myThread.setRun(false);  
         }  
}  


3、      主Activity修改view

public class TestSurfaceViewActivity extends Activity  
{  
    @Override  
    public void onCreate(Bundle savedInstanceState)  
    {  
        super.onCreate(savedInstanceState);  
        //setContentView(R.layout.main);  
        setContentView(new MySurfaceView(this));  
    }  
}

 

Tagged on:

发表评论

电子邮件地址不会被公开。 必填项已用*标注

您可以使用这些HTML标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>