Android SurfaceView

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.餘弦曲線:

相關文章
相關標籤/搜索