zoukankan      html  css  js  c++  java
  • Android中使用SurfaceView和Canvas来绘制动画

    事实上每一个View中都有Canvas能够用来绘制动画。仅仅须要在这个View中重载onDraw()方法就能够,可是SurfaceView类是一个专门用来制动动画的类。


    Canvas(中文叫做"画布")就和HTML5中的canvas标签一样能够在一定区域内自由绘制图形。Canvas+SurfaceView制作的动画与View Animation和Property Animation这类动画比起来更加适合大量的集中播放的动画,比方游戏画面、相机的图像显示等。


    由于SurfaceView一般会在还有一个专门的线程中不断重绘界面。所以不像其它动画那样要在主线程(UI线程)中播放动画的同一时候还要消耗一定的流畅度用来响应用户输入。


    在使用SurfaceView时须要注意以下这些要点:

    1)每一个SurfaceView都须要一个SurfaceHolder对象来处理这个SurfaceView的生命周期和获取这个SurfaceView的Canvas对象,能够通过调用SurfaceView的getHolder()方法来获取它的SurfaceHolder对象。


    2)使用SurfaceView时通常是通过继承SurfaceView的方式来实现,能够顺便implements两个接口,各自是Runnable和SurfaceHolder.Callback。第二个接口须要重载三个函数,这三个函数就是SurfaceView的生命周期处理了,能够通过SurfaceHolder对象的addCallback()方法把实现好的Callback对象传进去。


    3)在使用SurfaceView的Canvas时一定要记得加锁同步。由于不能让画布同一时候绘制多个图案,通过调用这个SurfaceView的SurfaceHolder对象的lockCanvas()就能够做到这一点。绘制完成后在调用SurfaceHolder对象的unlockCanvasAndPost()方法就能够解锁并更新。


    以下给出了一个用SurfaceView和Canvas绘制动画的样例,一般直接复制上就能够执行看到效果:

    package com.example.canvastest;
    
    import android.app.Activity;
    import android.content.Context;
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.graphics.Canvas;
    import android.graphics.Color;
    import android.graphics.Paint;
    import android.os.Bundle;
    import android.view.Menu;
    import android.view.SurfaceHolder;
    import android.view.SurfaceView;
    import android.widget.Toast;
    
    public class MainActivity extends Activity {
    	/*
    	 * 这个类用来当測试的物件,会沿着方形路线持续移动
    	 */
    	class GameObject {
    		private float x;
    		private float y;
    		private Bitmap img;
    		private Paint paint;
    
    		public GameObject() {
    			this.img = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
    			this.x = 100;
    			this.y = 100;
    			this.paint = new Paint();
    		}
    
    		// 在SurfaceView加锁同步后传给自己的Canvas上绘制自己
    		public void drawSelf(Canvas canvas) {
    			canvas.drawBitmap(img, x, y, paint);
    		}
    
    		// 获取物件下一次要绘制的位置(这里是沿着一个边长为400的正方形不断运动的)
    		public void getNextPos() {
    			if (y == 100 && x != 500)
    				x += 5;
    			else if (x == 500 && y != 500)
    				y += 5;
    			else if (y == 500 && x != 100)
    				x -= 5;
    			else if (x == 100 && y != 100)
    				y -= 5;
    		}
    	}
    
    	/*
    	 * 这个类就是加工了SurfaceView之后的类,全部要运动的物件都终于放在这里进行绘制
    	 */
    	class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback, Runnable {
    		private Thread thread; // SurfaceView通常须要自己单独的线程来播放动画
    		private Canvas canvas;
    		private SurfaceHolder surfaceHolder;
    
    		private GameObject obj;
    
    		public MySurfaceView(Context c) {
    			super(c);
    			this.surfaceHolder = this.getHolder();
    			this.surfaceHolder.addCallback(this);
    			this.obj = new GameObject();
    		}
    
    		@Override
    		public void run() {
    			while (true) {
    				obj.getNextPos();
    				canvas = this.surfaceHolder.lockCanvas(); // 通过lockCanvas加锁并得到該SurfaceView的画布
    				canvas.drawColor(Color.BLACK);
    				obj.drawSelf(canvas); // 把SurfaceView的画布传给物件。物件会用这个画布将自己绘制到上面的某个位置
    				this.surfaceHolder.unlockCanvasAndPost(canvas); // 释放锁并提交画布进行重绘
    				try {
    					Thread.sleep(10); // 这个就相当于帧频了,数值越小画面就越流畅
    				} catch (Exception e) {
    					e.printStackTrace();
    				}
    			}
    		}
    
    		@Override
    		public void surfaceDestroyed(SurfaceHolder arg0) {
    			Toast.makeText(getApplicationContext(), "SurfaceView已经销毁", Toast.LENGTH_LONG).show();
    		}
    
    		@Override
    		public void surfaceCreated(SurfaceHolder arg0) {
    			Toast.makeText(getApplicationContext(), "SurfaceView已经创建", Toast.LENGTH_LONG).show();
    			this.thread = new Thread(this);
    			this.thread.start();
    		}
    
    		@Override
    		public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
    			// 这里是SurfaceView发生变化的时候触发的部分
    		}
    	}
    
    	@Override
    	protected void onCreate(Bundle savedInstanceState) {
    		super.onCreate(savedInstanceState);
    		setContentView(new MySurfaceView(getApplicationContext())); // 别忘了開始的时候加载我们加工好的的SurfaceView
    	}
    
    	@Override
    	public boolean onCreateOptionsMenu(Menu menu) {
    		// Inflate the menu; this adds items to the action bar if it is present.
    		getMenuInflater().inflate(R.menu.main, menu);
    		return true;
    	}
    }
    


    假设转载请注明出处:http://blog.csdn.net/gophers



  • 相关阅读:
    Template(模板)模式
    Android活动(Activity)创建及生命周期
    Android--SharedPreferences数据存储方案
    Adapter适配器模式--图解设计模式
    准时制生产(Just in Time,JIT)
    术语
    制造资源计划(Manufacturing Resource Planning,Mrp II)
    Angualr6表单提交验证并跳转
    Android PDA扫描枪广播接搜条码并使用
    Java统计代码行数
  • 原文地址:https://www.cnblogs.com/mengfanrong/p/5175745.html
Copyright © 2011-2022 走看看