Android使用SurfaceView實現墨跡天氣的風車效果


    SurfaceView也是繼承自View,它和咱們之前接觸到的View(Button、TextView等)最大的不一樣是,SurfaceView能夠有一個單獨的線程進行繪製,這個線程區別於UI線程(主線程),所以SurfaceView繪製並不佔用主線程資源
html


    SurfaceView實現一般是自定義,繼承SurfaceView並實現SurfaceHolder.Callback接口。使用SurfaceView,全部的繪圖工做必須得在Surface 被建立以後才能開始,因此Callback 中的surfaceCreated 和surfaceDestroyed 就成了繪圖處理代碼的邊界。
java


實現SurfaceHolder.Callback接口須要重寫的方法:android

   //在surface的大小發生改變時激發
 (1)public void surfaceChanged(SurfaceHolder holder,int format,int width,int height){}
canvas

    //在建立時激發,通常在這裏調用畫圖的線程。
 (2)public void surfaceCreated(SurfaceHolder holder){}
ide

    //銷燬時激發,通常在這裏將畫圖的線程中止、釋放。    post

  (3)public void surfaceDestroyed(SurfaceHolder holder) {}this

    

SurfaceHolder有幾個重要方法:spa

// 鎖定畫布,通常在鎖定後就能夠經過其返回的畫布對象Canvas,在其上面畫圖等操做了。
(1)、abstract Canvas lockCanvas();
// 鎖定畫布的某個區域進行畫圖等..由於畫完圖後,會調用下面的unlockCanvasAndPost來改變顯示內容。
// 相對部份內存要求比較高的遊戲來講,能夠不用重畫dirty外的其它區域的像素,能夠提升速度。
(2)、abstract Canvas lockCanvas(Rect dirty);
// 結束鎖定畫圖,並提交改變。

(3)、abstract void unlockCanvasAndPost(Canvas canvas);.net

//給SurfaceView當前的持有者一個回調對象。線程

(4)、abstract void addCallback(SurfaceHolder.Callback callback);

下面使用SurfaceView實現墨跡天氣的風車效果:

public class WindmillView extends SurfaceView implements
		SurfaceHolder.Callback, Runnable {

	private SurfaceHolder holder;

	private boolean isRunning = true;

	

	/**
	 * 屏幕的像素
	 */
	private int screenWidth;
	private int screenHeiht;

	private Bitmap windPoint;

	/**
	 * 風車圖片
	 */
	private Bitmap Windmill;

	/**
	 * 背景圖片
	 */
	private Bitmap viewBg;

	public WindmillView(Context context) {
		super(context);
		this.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
				LayoutParams.MATCH_PARENT));
		holder = getHolder();
		holder.addCallback(this);
		holder.setFormat(PixelFormat.RGBA_8888); // 頂層繪製SurfaceView設成透明
		getViewSize(context);
		LoadWindmillImage();

	}

	private void LoadWindmillImage() {
		viewBg = BitmapFactory.decodeResource(getResources(), R.drawable.bg_na);
		Windmill = BitmapFactory.decodeResource(getResources(),
				R.drawable.na_windmill);
		windPoint = BitmapFactory.decodeResource(getResources(),
				R.drawable.na_point);
		float percent = percentumW();
		Log.v("icers", screenWidth + "");

		int _witdh = (int) (250 / percent);//250是風車基點左側像素
		Log.v("icers", _witdh + "");
		Windmill = Bitmap.createScaledBitmap(Windmill, _witdh * 2, _witdh * 2,
				true);

	}


	// 獲取屏幕的分辨率
	private void getViewSize(Context context) {
		DisplayMetrics metrics = new DisplayMetrics();
		WindowManager windowManager = (WindowManager) context
				.getSystemService(Context.WINDOW_SERVICE);
		windowManager.getDefaultDisplay().getMetrics(metrics);
		this.screenHeiht = metrics.heightPixels;
		this.screenWidth = metrics.widthPixels;

		Log.d("Windmill", "Windmill:"+screenHeiht+"|"+screenWidth);
	}

	/**
	 * 獲取背景圖和風車的比率 ,從而根據這個比例改變各個手機上面的風車圖片大小
	 * 
	 * 
	 * @return
	 */
	private float percentumW() {
		float bg_width = viewBg.getWidth();
		return  bg_width/screenWidth ;
	}
	/**
	 * 獲取背景圖和風車的比率 ,從而根據這個比例改變各個手機上面的風車圖片大小
	 * 
	 * 
	 * @return
	 */
	private float percentumH() {
		float bg_height = viewBg.getHeight();
		return  bg_height/(screenHeiht);
	}

	@Override
	public void run() {

		float rotate = 0;// 旋轉角度變量

		while (isRunning) {
			Log.i("icer", "Running");
			Canvas canvas = null;
			synchronized (this) {
				try {
					canvas = holder.lockCanvas();
					if (canvas != null) {
						Paint paint = new Paint();
						paint.setAntiAlias(true);

						// 對圖片抗鋸齒
						paint.setFilterBitmap(true);
						RectF rect = new RectF(0, 0, screenWidth, screenHeiht
								);
						canvas.drawBitmap(viewBg, null, rect, paint);
						Matrix matrix = new Matrix();
						matrix.postRotate((rotate += 2) % 360f,
								Windmill.getWidth() / 2,
								Windmill.getHeight() / 2);
						
						int _dy = (int) (500 /percentumH()); //500是風車基點到背景定點的像素
						matrix.postTranslate(0, (_dy - (Windmill.getHeight()/2)));
						canvas.drawBitmap(Windmill, matrix, paint);

						int _dx = (int) (250 / percentumW());//250是風車基點左側像素
						canvas.drawBitmap(windPoint,_dx-windPoint.getWidth()/2,_dy-windPoint.getHeight()/2,paint);
						Thread.sleep(3);
					}
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} finally {
					if (canvas != null) {
						holder.unlockCanvasAndPost(canvas);
					}
				}

			}

		}

	}

	public void setRunning(boolean state) {
		isRunning = state;

	}

	@Override
	public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
		// TODO Auto-generated method stub

	}

	@Override
	public void surfaceCreated(SurfaceHolder arg0) {

		new Thread(this).start();
	}

	@Override
	public void surfaceDestroyed(SurfaceHolder arg0) {
		// TODO Auto-generated method stub
		isRunning = false;

	}

}


 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        WindmillView view=new WindmillView(this);
		setContentView(view);
    }


    整個過程:繼承SurfaceView並實現SurfaceHolder.Callback接口 ----> SurfaceView.getHolder()得到SurfaceHolder對象 ---->SurfaceHolder.lockCanvas()得到Canvas對象並鎖定畫布----> Canvas繪畫 ---->SurfaceHolder.unlockCanvasAndPost(Canvas canvas)結束鎖定畫圖,並提交改變,將圖形顯示。


* @author 張興業
*  http://blog.csdn.net/xyz_lmn
*  iOS入門羣: 83702688
*  android開發進階羣: 241395671
*  個人新浪微博: @張興業TBOW
*/


參考:

http://www.cnblogs.com/plokmju/p/android_SurfaceView.html

http://developer.android.com/reference/android/view/SurfaceView.html

http://blog.csdn.net/luoshengyang/article/details/8661317

http://blog.csdn.net/hellogv/article/details/5986835

http://developer.android.com/reference/android/view/SurfaceHolder.html

相關文章
相關標籤/搜索