理解自製SurfaceView代碼

來源:互聯網
上載者:User

概述:

            最近在讀himi的android遊戲開發專欄,其中通過前幾張剖析View的繼承介面類發現SurfaceView比較適合做Game Dev然後本人也動手跟著himi的代碼敲了幾下。最終雖然也達到了himi的運行效果。但是其中還是經過了好多疑點。現在本人將自己的理解發布出來,歡迎交流與學習

 


Code List:


[java]
import android.content.Context; 
import android.content.Intent; 
import android.content.res.Resources; 
import android.graphics.Bitmap; 
import android.graphics.BitmapFactory; 
import android.graphics.Canvas; 
import android.graphics.Color; 
import android.graphics.Paint; 
import android.util.Log; 
import android.view.MotionEvent; 
import android.view.SurfaceHolder; 
import android.view.SurfaceHolder.Callback; 
import android.view.SurfaceView; 
 
public class LoginView extends SurfaceView implements Callback,Runnable{ 
 
    private Canvas canvas;  //定義畫布對象  
    private Thread thread;  //定義線程線程對應  
    private int ScreenW,ScreenH;    //定義螢幕的寬度和高度  
    private Paint paint;    //定義畫筆對象  
    private SurfaceHolder sh;   //聲明SurfaceHolder對象  
    private Resources resources;    //聲明資來源物件  
    private Bitmap bitmapr; //註冊bitmap  
    private Bitmap bitmapb; //背景bitmap  
    private int bp_x,bp_y;  //註冊背景圖寬度高�?  
    private boolean flag;    
    public static String zh_k = "註冊頁面"; 
    private boolean zh_flag = true;  
    private String str_pass = "aaa"; 
    //初始構�?  
    public LoginView(Context context) { 
        super(context); 
        //  
        resources = this.getResources(); 
        bitmapr = BitmapFactory.decodeResource(resources, R.drawable.register); //註冊視窗  
        bitmapb = BitmapFactory.decodeResource(resources, R.drawable.duola);    //註冊背景�?  
        thread = new Thread(this); 
        sh = this.getHolder(); 
        sh.addCallback(this); 
        paint = new Paint(); 
        paint.setColor(Color.RED); 
        paint.setAntiAlias(true);   //去掉鋸齒  
        this.setFocusable(true);     
        this.setKeepScreenOn(true);     //設定螢幕常亮  
        resources = this.getResources(); 
         
    } 
    public void draw(){ 
        canvas = sh.lockCanvas();   //得到畫布對象  
        paint.setColor(Color.RED); 
        if(null != canvas){         //在設定橫屏的時候 座標演算法如下  
            canvas.drawColor(Color.WHITE); 
            canvas.drawBitmap(bitmapb,       
                    -(bitmapb.getWidth() - ScreenW), -(bitmapb 
                            .getHeight() - ScreenH), paint); 
            //2、3參數為x座標和y座標,就是位元影像paint的左上方位置  
            canvas.drawBitmap(bitmapr, bp_x,bp_y, paint); 
            sh.unlockCanvasAndPost(canvas); 
        } 
    } 
    @Override 
    public void run() { 
        while(!flag){ 
            draw(); 
            try { 
                thread.sleep(1000); 
            } catch (Exception e) { 
                Log.v("run", "error"); 
            } 
        } 
    } 
    @Override 
    public void surfaceCreated(SurfaceHolder holder) { 
        ScreenW = this.getWidth(); 
        ScreenH = this.getHeight(); 
        bp_x = ScreenW/2-bitmapr.getWidth()/2; 
        bp_y = ScreenH/2-bitmapr.getHeight()/2; 
        thread.start(); 
    } 
    @Override 
    public void surfaceChanged(SurfaceHolder holder, int format, int width, 
            int height) { 
         
    } 
    @Override 
    public void surfaceDestroyed(SurfaceHolder holder) { 
         
    } 
    @Override 
    public boolean onTouchEvent(MotionEvent event) { 
        float x = event.getX();      
        float y = event.getY(); 
         
        if(x > bp_x+14 && x < bp_x+129){  //鎖定登陸框姓名地區X軸  
            if(y >= bp_y+43 && y <= bp_y+58){ //鎖定登陸框姓名地區Y軸  
                Intent intent = new Intent(); 
                intent.putExtra("name", "zhanglei"); 
                intent.setClass(MainActivity.instance, Register.class); 
                MainActivity.instance.startActivity(intent); 
            } 
        } 
        return super.onTouchEvent(event); 
    } 

import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;

public class LoginView extends SurfaceView implements Callback,Runnable{

 private Canvas canvas; //定義畫布對象
 private Thread thread; //定義線程線程對應
 private int ScreenW,ScreenH; //定義螢幕的寬度和高度
 private Paint paint; //定義畫筆對象
 private SurfaceHolder sh; //聲明SurfaceHolder對象
 private Resources resources; //聲明資來源物件
 private Bitmap bitmapr; //註冊bitmap
 private Bitmap bitmapb; //背景bitmap
 private int bp_x,bp_y; //註冊背景圖寬度高�?
 private boolean flag; 
 public static String zh_k = "註冊頁面";
 private boolean zh_flag = true; 
 private String str_pass = "aaa";
 //初始構�?
 public LoginView(Context context) {
  super(context);
  //
  resources = this.getResources();
  bitmapr = BitmapFactory.decodeResource(resources, R.drawable.register); //註冊視窗
  bitmapb = BitmapFactory.decodeResource(resources, R.drawable.duola); //註冊背景�?
  thread = new Thread(this);
  sh = this.getHolder();
  sh.addCallback(this);
  paint = new Paint();
  paint.setColor(Color.RED);
  paint.setAntiAlias(true); //去掉鋸齒
  this.setFocusable(true); 
  this.setKeepScreenOn(true);  //設定螢幕常亮
  resources = this.getResources();
  
 }
 public void draw(){
  canvas = sh.lockCanvas(); //得到畫布對象
  paint.setColor(Color.RED);
  if(null != canvas){   //在設定橫屏的時候 座標演算法如下
   canvas.drawColor(Color.WHITE);
   canvas.drawBitmap(bitmapb,  
     -(bitmapb.getWidth() - ScreenW), -(bitmapb
       .getHeight() - ScreenH), paint);
   //2、3參數為x座標和y座標,就是位元影像paint的左上方位置
   canvas.drawBitmap(bitmapr, bp_x,bp_y, paint);
   sh.unlockCanvasAndPost(canvas);
  }
 }
 @Override
 public void run() {
  while(!flag){
   draw();
   try {
    thread.sleep(1000);
   } catch (Exception e) {
    Log.v("run", "error");
   }
  }
 }
 @Override
 public void surfaceCreated(SurfaceHolder holder) {
  ScreenW = this.getWidth();
  ScreenH = this.getHeight();
  bp_x = ScreenW/2-bitmapr.getWidth()/2;
  bp_y = ScreenH/2-bitmapr.getHeight()/2;
  thread.start();
 }
 @Override
 public void surfaceChanged(SurfaceHolder holder, int format, int width,
   int height) {
  
 }
 @Override
 public void surfaceDestroyed(SurfaceHolder holder) {
  
 }
 @Override
 public boolean onTouchEvent(MotionEvent event) {
  float x = event.getX();  
  float y = event.getY();
  
  if(x > bp_x+14 && x < bp_x+129){ //鎖定登陸框姓名地區X軸
   if(y >= bp_y+43 && y <= bp_y+58){ //鎖定登陸框姓名地區Y軸
    Intent intent = new Intent();
    intent.putExtra("name", "zhanglei");
    intent.setClass(MainActivity.instance, Register.class);
    MainActivity.instance.startActivity(intent);
   }
  }
  return super.onTouchEvent(event);
 }
}


運行:

 

 


方法執行順序:

LoginView-->surfaceCreated-->run-->draw

 


方法解析:

LoginView方法:

OK,我們看到LoginView其實是在初始化本View的一些全域變數,包括線程對象、位元影像對象。另外設定了一些效果,包括去掉鋸齒等。程式中注釋特別明朗

surfaceCreated方法:


本方法體中我們看到初始化了2組長度和高度。其中Sreen顧名思義我就不再解釋。bp_x和bp_y指的是註冊圖片在螢幕中的開始座標的位置。也就是左上方的位置[演算法解析:“螢幕的一半座標為中心點座標-註冊圖片一半的像素值”]得到的就為繪製圖片位元影像的起始位置。你明白了嗎?

run方法:


run方法為thread線程開始的跑的標示,代碼邏輯很簡單不再解釋

draw方法:


OK,本人覺得draw方法才是一個View中最核心的內容。因為它負責在螢幕上繪製內容和重新整理內容。本人將himi部落格的內容簡單化了很多。應該很好理解吧。

拿到canvas到畫兩個位元影像其中的注釋寫的很清楚本人不再多說

 


注意:

本人在做此案例的時候遇到了1個特別棘手的問題那就是按照himi的原始碼自己new的一個項目居然在paint位元影像的時候遇到了錯亂的問題。

 

 

說明:

登陸視窗的使用者名稱和密碼的點擊事件是通過重寫onTouchEvent方法來實現的。鎖定了相關的像素座標地區。如果該地區被點擊了就發送一個Intent。其中Intent的傳參為put的那個方法,另外在AndroidManifest.xml檔案中注意聲明你Intent跳轉的Activity

 


聲明:本人也是一名Android新手,歡迎大家一起交流與學習。稍後本人將發布本博文的源碼地址。因為公司網路不好,可能會在晚上回家之後upload上去

 


 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.