SurfaceView 是View的繼承類,這個視圖裏內嵌了一個專門用於繪製的Surface。能夠控制這個Surface的格式和尺寸。SurfaceView控制這個Surface的繪製位置
SurfaceView:基於view視圖進行拓展的視圖類,更適合2D遊戲的開發;是view的子類,類上使用雙緩衝機制,在新的線程中更新畫面因此新界面速度比view快。java
Surface是縱深排序的,這說明它總在本身所在的窗口的後面。SurfaceView 提供了一個可見區域,只有在這個可見區域內的surface部份內容纔可見,可見區域外部部分不可 見。surface的排版顯示受到視圖層級關係的影響,它的兄弟節點會在頂端顯示。這意味者surface的內容會被它的兄弟視圖遮擋,這一特性能夠用來放置遮蓋物(overlays)(例如:文本和按鈕等控件)。可是,當surface上面有透明控件時,它的每次變化都會引發框架從新計算它和頂層控件的透明效果,這會影響性能。能夠經過SurfaceHolder接口訪問這個surface,getHolder()方法能夠獲得這個接口linux
Surfaceview變的可見時,surface被建立,surfaceView隱藏前,surface被毀滅。這樣能夠節省資源。surface建立:surfaceCreated(SurfaceHolder)和surfaceDestroyed(SurfaceHolder).android
SurfaceView的核心提供了兩個線程:UI線程和渲染線程。應該注意的是:canvas
a.全部的SurfaceView和SurfaceHolder.Callback的方法都應該在UI線程裏調用,通常來講就是應用程序的主線程。渲染線程所要訪問的各類變量應該作同步處理。app
b.因爲surface可能被銷燬,它只在SurfaceHolder.Callback.surfaceCreated()和SurfaceHoledr.Callback.surfaceDestroyed()之間有效,因此要確保渲染線程訪問的是合法有效地surface.框架
2、SurfaceView類 和View類的區別ide
SurfaceView 和View的最本質的區別在於,surfaceView是在一個在新起的單獨線程中能夠從新繪製畫面,而View必須在UI的主線程中更新畫面。那麼在UI的主線程中更新畫面,可能會引起問題,好比你更新畫面的時間過長,那麼你的主UI線程會被你正在畫的函數阻塞,那麼將沒法響應按鍵,觸摸等消息。當使用surfaceView因爲是在新的線程中更新畫面因此不會阻塞你的UI主線程,可是這也會有另一個問題,就是事件同步。好比你觸屏了一下,你須要surfaceView中thread處理,通常就須要有一個event queue的設計來保存touch event,這樣就會有點複雜了。函數
View:必須在UI的主線程中更新畫面,用於被動更新畫面。佈局
surfaceView:UI線程和子線程中均可以。在一個新啓動的線程中從新繪製畫面,主動更新畫面。性能
因此在遊戲的應用上,根據遊戲的特色,通常分爲兩類:
a. 被動更新畫面的。好比棋類,這種用view就好。由於畫面的跟新依賴於onTouch來更新,能夠直接使用invalidate.由於這種狀況下,這一次Touch和下一次Touch須要的時間比較長些,不會產生
影響。
b.主動更新:好比一我的在一直跑動。這就須要一個單獨的thread不停地重繪人的轉檯,避免阻塞mian UI Thread 。因此顯然view 不適合,須要surfaceView來控制。
(1.)定義:
能夠直接從內存或者DMA等硬件接口取得圖像數據,是個很是重要的繪圖容器。
它的特性:能夠在主線程以外的線程中向屏幕繪圖上。這樣能夠避免畫圖任務繁重時形成主線程阻塞,從而提升了程序的反應速度。在遊戲開發中多用到SurfaceView,遊戲中的背景、人物、動畫等等儘可能在畫布canvas中畫出。
SurfaceView提供直接訪問一個可畫圖的界面,能夠控制在界面頂部的子視圖層。SurfaceView是提供給須要直接畫像素而不是使用窗體不見的應用使用的。Android系統中一個重要的概念和線索是Surface.View及其子類(TextView,Button等)要畫在Surface上。每一個Surface建立一個Canvas對象(但屬性時常改變),用來管理view在Surface上的繪圖操做,如畫點畫線,使用它是,通常都是出如今
最頂層。
(2.)實現
首先繼承SurfaceView並實現SurfaceHolder.Callback接口
使用接口的緣由:由於使用SurfaceView有一個原則,全部的繪圖工做必須得在Surface被建立以後才能開始(Surface能夠看成顯存的一個映射,寫入到Surface的內容,能夠被直接複製到顯存中從而顯示出來,這使得顯示的速度會很是快),而在Surface被銷燬以前必須結束。因此CallBack中的surfaceCreated和surfaceDestroyed就成了繪圖代理代碼的邊界。
須要重寫的方法:
a. public void sufaceChanged(SurfaceHolder holder,int format,int width,int height){}//Surface的大小發生改變時調用
b. public void surfaceCreated(SurfaceHolder holder){}//Surface建立時激發,通常在這裏調用畫面的線程。
c. public void surfaceDestroyed(SurfaceHolder holder){}//銷燬時激發,通常在這裏將畫面的線程中止、釋放。
d. public void addCallback{};//給SurfaceView添加一個回調函數。
e. public void lockCanvas{};//鎖定畫布。繪圖以前必須鎖定畫布纔可以獲得畫布對象。
f. public void unlockCanvasAndPost{};//開始繪製時鎖定了畫布,繪製完成後解鎖畫布。
g. public void removeCallback:從SurfaceView中移除回調函數。
SurfaceView不一樣View之處在於,SurfaceView不須要經過線程來更新視圖,可是再繪製前須要使用locakCanvas鎖定畫布,而且獲得畫布,而後再畫布上繪製你須要的圖像。繪製完成後須要使用lockCanvasAndPost方法來解鎖畫布。因而才能顯示在屏幕上。事件的處理規則和View是同樣的。
整個實現過程:
繼承SurfaceView並實現SurfaceHolder.Callback接口------>SurfaceView.getHolder()得到SurfaceHolder對象----->SurfaceHolder.addCallback(callback)添加回調函數----->
surfaceHolder.lockCanvas()得到Canvas對象並鎖定畫布------>Canvas繪畫------->SurfaceHolder.unlockCanvasAndPost(Canvas canvas)結束鎖定畫圖,並提交改變,將圖形顯示。
(3.)SurfaceHolder:
這裏用到了一個類SurfaceHolder,能夠把它當成surface的控制器,用來操縱surface。處理它的Canvas上畫的效果和動畫,控制表面,大小,像素等。
幾個經常使用的方法:
a.abstract void addCallback(SurfaceHolder.Callbask callback);//給SurfaceView當前的持有者一個回調函數。
b.abstract Canvas lockCanvas();//鎖定畫布,通常在鎖定後就能夠經過其返回的畫布對象Canvas,在其上面等操縱了。
c.abstract Canvas lockCanvas(Rect dirty);//鎖定畫布的某個區域進行畫圖等..由於畫完圖後,會調用下面的unlockCanvasAndPost()來改變顯示的內容。相對部份內存要求比較高的遊戲來講, 能夠不用重畫dirty外的其餘區域的像素,能夠提升速度。
d.abstract void unlockCanvasAndPost(Canvas canvas);//結束鎖定畫圖,並提交改變。
最後經過一個SurfaceView開發一個示波器的例子,來結束SurfaceView吧(代碼太多,放在下一頁中 http://www.linuxidc.com/Linux/2012-05/61202p3.htm ),謝謝
SurfaceView 示波器的例子:直接上代碼了就
該程序會根據單擊的按鈕在屏幕上自動繪製正弦波和餘弦波形。程序每次繪製時只須要繪製(更新)當前點的波形,前面已經繪製的波形無須更新,利用了SurfaceHolder的lockCanvas(Rect r)方法
1.佈局文件Layout/show_wave.xml:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:Android="http://schemas.android.com/apk/res/android" android:orientation ="vertical" android:layout_width="wrap_content" android:layout_height="wrap_content"> <Button android:id="@+id/sin" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="正弦曲線" /> <Button android:id="@+id/cos" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="餘弦曲線" /> <SurfaceView android:id="@+id/show" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout>
2.主界面Activity:ShowWave
package com.infy.configuration; import java.util.Timer; import java.util.TimerTask; import Android.app.Activity; 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; import android.view.View; import android.view.SurfaceHolder.Callback; import android.view.View.OnClickListener; import android.widget.Button; public class ShowWave extends Activity{ private SurfaceHolder holder; private Paint paint; final int HEIGHT=320; final int WIDTH=320; final int X_OFFSET = 5; private int cx = X_OFFSET; //實際的Y軸的位置 int centerY = HEIGHT /2; Timer timer = new Timer(); TimerTask task = null; @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); setContentView(R.layout.show_wave); final SurfaceView surface = (SurfaceView)findViewById(R.id.show); //初始化SurfaceHolder對象 holder = surface.getHolder(); paint = new Paint(); paint.setColor(Color.GREEN); paint.setStrokeWidth(3); Button sin =(Button)findViewById(R.id.sin); Button cos =(Button)findViewById(R.id.cos); OnClickListener listener = (new OnClickListener() { @Override public void onClick(final View source) { // TODO Auto-generated method stub drawBack(holder); cx = X_OFFSET; if(task != null){ task.cancel(); } task = new TimerTask() { @Override public void run() { int cy = source.getId() == R.id.sin ? centerY -(int)(100 * Math.sin((cx -5) *2 * Math.PI/150)): centerY -(int)(100 * Math.cos((cx-5)*2*Math.PI/150)); Canvas canvas = holder.lockCanvas(new Rect(cx,cy-2,cx+2,cy+2)); canvas.drawPoint(cx, cy, paint); cx++; if(cx >WIDTH){ task.cancel(); task = null; } holder.unlockCanvasAndPost(canvas); } }; timer.schedule(task, 0,30); } }); sin.setOnClickListener(listener); cos.setOnClickListener(listener); holder.addCallback(new Callback() { public void surfaceChanged(SurfaceHolder holder,int format,int width,int height){ drawBack(holder); } @Override public void surfaceCreated(SurfaceHolder holder) { // TODO Auto-generated method stub } @Override public void surfaceDestroyed(SurfaceHolder holder) { // TODO Auto-generated method stub timer.cancel(); } }); } private void drawBack(SurfaceHolder holder){ Canvas canvas = holder.lockCanvas(); //繪製白色背景 canvas.drawColor(Color.WHITE); Paint p = new Paint(); p.setColor(Color.BLACK); p.setStrokeWidth(2); //繪製座標軸 canvas.drawLine(X_OFFSET, centerY, WIDTH, centerY, p); canvas.drawLine(X_OFFSET, 40, X_OFFSET, HEIGHT, p); holder.unlockCanvasAndPost(canvas); holder.lockCanvas(new Rect(0,0,0,0)); holder.unlockCanvasAndPost(canvas); } }
3.最後顯示結果:
a.正弦曲線
b.餘弦曲線: