extends View
↳ |
||
|
↳ |
android.view.SurfaceView |
由手冊可知:
SurfaceView是View類的繼承類,這個View裏內嵌了一個專門用於繪製的Surface,這個可以類似的理解成爲一個在View裏的Canvas。你可以控制這個Surface的格式和尺寸。Surfaceview類則控制這個Surface在屏幕上的正確位置。
《Android高級編程》裏說:
在一般情況下,應用程序的View都是在相同的GUI線程中繪製的。這個主應用程序線程同時也用來處理所有的用戶交互(例如按鈕單擊或者文本輸入)。
對於一個View的onDraw()方法,不能夠滿足將其移動到後臺線程中去。因爲從後臺線程修改一個GUI元素會被顯式地禁止的。
當需要快速地更新View的UI,或者當前渲染代碼阻塞GUI線程的時間過長的時候,SurfaceView就是解決上述問題的最佳選擇。SurfaceView封裝了一個Surface對象,而不是Canvas。這一點很重要,因爲Surface可以使用後臺線程繪製。對於那些資源敏感的操作,或者那些要求快速更新或者高速幀率的地方,例如使用3D圖形,創建遊戲,或者實時預覽攝像頭,這一點特別有用。
1. 何時應該使用SurfaceView
SurfaceView使用的方式與任何View所派生的類都是完全相同的。可以像其他View那樣應用動畫,並把它們放到佈局中。
SurfaceView封裝的Surface支持所有標準的Canvas方法進行繪圖,同時也支持完全的OpenGL ES 庫。
使用OpenGL,你可以在Surface上繪製任何支持2D或者3D對象,與在2D畫布上模擬相同的效果相比,這種方法可以依靠硬件加速(可用的時候)來極大地提高性能。
對於顯示動態的3D圖像來說,例如,那些使用Google Earth 功能的應用程序,或者那些提供沉浸體驗的交互式遊戲,Surface特別有用。它還是實時顯示攝像頭預覽的最佳選擇。
2. 創建一個新的SurfaceView控件
創建一個新的SurfaceView控件需要創建一個新的擴展了SurfaceView的類,並實現SurfaceHolder.Callback。
SurfaceHolder回調可以在底層的Surface被創建和銷燬的時候通知View,並傳遞給它SurfaceHolder對象的引用,其中包含了當前有效的Surface。
一個典型的SurfaceView 設計模型包括一個由Thread所派生的類,它可以接收對當前的SurfaceHolder的引用,並獨立地更新它。
3. 使用SurfaceView創建3D控件
Android完全支持OpenGL ES 3D 渲染框架,其中包含了對設備的硬件加速的支持。SurfaceView控件提供了一個表面,可以在它上面渲染你的OpenGL場景。
關於SurfaceView的使用
被動更新畫面的。比如棋類,這種用view就好了。因爲畫面的更新是依賴於 onTouch 來更新,可以直接使用 invalidate。 因爲這種情況下,這一次Touch和下一次的Touch需要的時間比較長些,不會產生影響。
主動更新。比如一個人在一直跑動。這就需要一個單獨的thread不停的重繪人的狀態,避免阻塞main UI thread。所以顯然view不合適,需要surfaceView來控制。
它的特性是:可以在主線程之外的線程中向屏幕繪圖。這樣可以避免畫圖任務繁重的時候造成主線程阻塞,從而提高了程序的反應速度。
如何去使用一個SurfaceView:
首先繼承SurfaceView並實現SurfaceHolder.Callback接口。因爲使用SurfaceView 有一個原則,所有的繪圖工作必須得在Surface 被創建之後才能開始。可以被直接複製到顯存從而顯示出來,這使得顯示速度會非常快,而在Surface 被銷燬之前必須結束。所以Callback 中的surfaceCreated 和surfaceDestroyed 就成了繪圖處理代碼的邊界。
需要重寫的方法
(1)public void surfaceChanged(SurfaceHolder holder,int format,int width,int height){}
//在surface的大小發生改變時激發
(2)public void surfaceCreated(SurfaceHolder holder){}
//在創建時激發,一般在這裏調用畫圖的線程。
(3)public void surfaceDestroyed(SurfaceHolder holder) {}
//銷燬時激發,一般在這裏將畫圖的線程停止、釋放。
整個過程:繼承SurfaceView並實現SurfaceHolder.Callback接口 ----> SurfaceView.getHolder()獲得SurfaceHolder對象 ---->SurfaceHolder.addCallback(callback)添加回調函數---->SurfaceHolder.lockCanvas()獲得Canvas對象並鎖定畫布----> Canvas繪畫 ---->SurfaceHolder.unlockCanvasAndPost(Canvas canvas)結束鎖定畫圖,並提交改變,將圖形顯示。
關於SurfaceHolder:
這裏用到了一個類SurfaceHolder,可以把它當成surface的控制器,用來操縱surface。處理它的Canvas上畫的效果和動畫,控制表面,大小,像素等。
(1)、abstract void addCallback(SurfaceHolder.Callback callback);
// 給SurfaceView當前的持有者一個回調對象。
(2)、abstract Canvas lockCanvas();
// 鎖定畫布,一般在鎖定後就可以通過其返回的畫布對象Canvas,在其上面畫圖等操作了。
(3)、abstract Canvas lockCanvas(Rect dirty);
// 鎖定畫布的某個區域進行畫圖等..因爲畫完圖後,會調用下面的unlockCanvasAndPost來改變顯示內容。
// 相對部分內存要求比較高的遊戲來說,可以不用重畫dirty外的其它區域的像素,可以提高速度。
(4)、abstract void unlockCanvasAndPost(Canvas canvas);
// 結束鎖定畫圖,並提交改變。
測試代碼:
- package com.blueeagle;
- import android.app.Activity;
- import android.content.Context;
- import android.graphics.Canvas;
- import android.graphics.Color;
- import android.graphics.Paint;
- import android.graphics.Rect;
- import android.os.Bundle;
- import android.view.SurfaceHolder;
- import android.view.SurfaceView;
- public class SurfaceView01 extends Activity {
- /** Called when the activity is first created. */
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(new MyView(this));
- }
- //視圖內部類
- class MyView extends SurfaceView implements SurfaceHolder.Callback
- {
- private SurfaceHolder holder;
- private MyThread myThread;
- public MyView(Context context) {
- super(context);
- // TODO Auto-generated constructor stub
- holder = this.getHolder();
- holder.addCallback(this);
- myThread = new MyThread(holder);//創建一個繪圖線程
- }
- @Override
- public void surfaceChanged(SurfaceHolder holder, int format, int width,
- int height) {
- // TODO Auto-generated method stub
- }
- @Override
- public void surfaceCreated(SurfaceHolder holder) {
- // TODO Auto-generated method stub
- myThread.isRun = true;
- myThread.start();
- }
- @Override
- public void surfaceDestroyed(SurfaceHolder holder) {
- // TODO Auto-generated method stub
- myThread.isRun = false;
- }
- }
- //線程內部類
- class MyThread extends Thread
- {
- private SurfaceHolder holder;
- public boolean isRun ;
- public MyThread(SurfaceHolder holder)
- {
- this.holder =holder;
- isRun = true;
- }
- @Override
- public void run()
- {
- int count = 0;
- while(isRun)
- {
- Canvas c = null;
- try
- {
- synchronized (holder)
- {
- c = holder.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);
- Thread.sleep(1000);//睡眠時間爲1秒
- }
- }
- catch (Exception e) {
- // TODO: handle exception
- e.printStackTrace();
- }
- finally
- {
- if(c!= null)
- {
- holder.unlockCanvasAndPost(c);//結束鎖定畫圖,並提交改變。
- }
- }
- }
- }
- }
- }