Android自定義view--SurfaceView實現墨跡天氣的風車效果



 Android自定義view--SurfaceView實現墨跡天氣的風車效果


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


    SurfaceView實現通常是自定義,繼承SurfaceView並實現SurfaceHolder.Callback接口。使用SurfaceView,所有的繪圖工作必須得在Surface 被創建之後才能開始,所以Callback 中的surfaceCreated 和surfaceDestroyed 就成了繪圖處理代碼的邊界。


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

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

    //在創建時激發,一般在這裏調用畫圖的線程。
 (2)public void surfaceCreated(SurfaceHolder holder){}

    //銷燬時激發,一般在這裏將畫圖的線程停止、釋放。    

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

    

SurfaceHolder有幾個重要方法:

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

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

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

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

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

  1. public class WindmillView extends SurfaceView implements  
  2.         SurfaceHolder.Callback, Runnable {  
  3.   
  4.     private SurfaceHolder holder;  
  5.   
  6.     private boolean isRunning = true;  
  7.   
  8.       
  9.   
  10.     /** 
  11.      * 屏幕的像素 
  12.      */  
  13.     private int screenWidth;  
  14.     private int screenHeiht;  
  15.   
  16.     private Bitmap windPoint;  
  17.   
  18.     /** 
  19.      * 風車圖片 
  20.      */  
  21.     private Bitmap Windmill;  
  22.   
  23.     /** 
  24.      * 背景圖片 
  25.      */  
  26.     private Bitmap viewBg;  
  27.   
  28.     public WindmillView(Context context) {  
  29.         super(context);  
  30.         this.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,  
  31.                 LayoutParams.MATCH_PARENT));  
  32.         holder = getHolder();  
  33.         holder.addCallback(this);  
  34.         holder.setFormat(PixelFormat.RGBA_8888); // 頂層繪製SurfaceView設成透明  
  35.         getViewSize(context);  
  36.         LoadWindmillImage();  
  37.   
  38.     }  
  39.   
  40.     private void LoadWindmillImage() {  
  41.         viewBg = BitmapFactory.decodeResource(getResources(), R.drawable.bg_na);  
  42.         Windmill = BitmapFactory.decodeResource(getResources(),  
  43.                 R.drawable.na_windmill);  
  44.         windPoint = BitmapFactory.decodeResource(getResources(),  
  45.                 R.drawable.na_point);  
  46.         float percent = percentumW();  
  47.         Log.v("icers", screenWidth + "");  
  48.   
  49.         int _witdh = (int) (250 / percent);//250是風車基點左側像素  
  50.         Log.v("icers", _witdh + "");  
  51.         Windmill = Bitmap.createScaledBitmap(Windmill, _witdh * 2, _witdh * 2,  
  52.                 true);  
  53.   
  54.     }  
  55.   
  56.   
  57.     // 獲取屏幕的分辨率  
  58.     private void getViewSize(Context context) {  
  59.         DisplayMetrics metrics = new DisplayMetrics();  
  60.         WindowManager windowManager = (WindowManager) context  
  61.                 .getSystemService(Context.WINDOW_SERVICE);  
  62.         windowManager.getDefaultDisplay().getMetrics(metrics);  
  63.         this.screenHeiht = metrics.heightPixels;  
  64.         this.screenWidth = metrics.widthPixels;  
  65.   
  66.         Log.d("Windmill""Windmill:"+screenHeiht+"|"+screenWidth);  
  67.     }  
  68.   
  69.     /** 
  70.      * 獲取背景圖和風車的比率 ,從而根據這個比例改變各個手機上面的風車圖片大小 
  71.      *  
  72.      *  
  73.      * @return 
  74.      */  
  75.     private float percentumW() {  
  76.         float bg_width = viewBg.getWidth();  
  77.         return  bg_width/screenWidth ;  
  78.     }  
  79.     /** 
  80.      * 獲取背景圖和風車的比率 ,從而根據這個比例改變各個手機上面的風車圖片大小 
  81.      *  
  82.      *  
  83.      * @return 
  84.      */  
  85.     private float percentumH() {  
  86.         float bg_height = viewBg.getHeight();  
  87.         return  bg_height/(screenHeiht);  
  88.     }  
  89.   
  90.     @Override  
  91.     public void run() {  
  92.   
  93.         float rotate = 0;// 旋轉角度變量  
  94.   
  95.         while (isRunning) {  
  96.             Log.i("icer""Running");  
  97.             Canvas canvas = null;  
  98.             synchronized (this) {  
  99.                 try {  
  100.                     canvas = holder.lockCanvas();  
  101.                     if (canvas != null) {  
  102.                         Paint paint = new Paint();  
  103.                         paint.setAntiAlias(true);  
  104.   
  105.                         // 對圖片抗鋸齒  
  106.                         paint.setFilterBitmap(true);  
  107.                         RectF rect = new RectF(00, screenWidth, screenHeiht  
  108.                                 );  
  109.                         canvas.drawBitmap(viewBg, null, rect, paint);  
  110.                         Matrix matrix = new Matrix();  
  111.                         matrix.postRotate((rotate += 2) % 360f,  
  112.                                 Windmill.getWidth() / 2,  
  113.                                 Windmill.getHeight() / 2);  
  114.                           
  115.                         int _dy = (int) (500 /percentumH()); //500是風車基點到背景定點的像素  
  116.                         matrix.postTranslate(0, (_dy - (Windmill.getHeight()/2)));  
  117.                         canvas.drawBitmap(Windmill, matrix, paint);  
  118.   
  119.                         int _dx = (int) (250 / percentumW());//250是風車基點左側像素  
  120.                         canvas.drawBitmap(windPoint,_dx-windPoint.getWidth()/2,_dy-windPoint.getHeight()/2,paint);  
  121.                         Thread.sleep(3);  
  122.                     }  
  123.                 } catch (InterruptedException e) {  
  124.                     // TODO Auto-generated catch block  
  125.                     e.printStackTrace();  
  126.                 } finally {  
  127.                     if (canvas != null) {  
  128.                         holder.unlockCanvasAndPost(canvas);  
  129.                     }  
  130.                 }  
  131.   
  132.             }  
  133.   
  134.         }  
  135.   
  136.     }  
  137.   
  138.     public void setRunning(boolean state) {  
  139.         isRunning = state;  
  140.   
  141.     }  
  142.   
  143.     @Override  
  144.     public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {  
  145.         // TODO Auto-generated method stub  
  146.   
  147.     }  
  148.   
  149.     @Override  
  150.     public void surfaceCreated(SurfaceHolder arg0) {  
  151.   
  152.         new Thread(this).start();  
  153.     }  
  154.   
  155.     @Override  
  156.     public void surfaceDestroyed(SurfaceHolder arg0) {  
  157.         // TODO Auto-generated method stub  
  158.         isRunning = false;  
  159.   
  160.     }  
  161.   
  162. }  


  1. @Override  
  2.    protected void onCreate(Bundle savedInstanceState) {  
  3.        super.onCreate(savedInstanceState);  
  4.          
  5.        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);  
  6.        requestWindowFeature(Window.FEATURE_NO_TITLE);  
  7.        WindmillView view=new WindmillView(this);  
  8.     setContentView(view);  
  9.    }  


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



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章