android圖像繪制(四)——SurfaceView問題,自定義控件

自定義控件(類似按鈕等)的使用,自定義一個SurfaceView。

如某一塊的動態圖(自定義相應),或者類似UC瀏覽器下面的工具欄。

如下圖示例:

 

 

自定義類代碼:

[java]
public class ImageSurfaceView extends SurfaceView implements Callback{ 
    //用於控制SurfaceView  
    private SurfaceHolder sfh; 
    private Handler handler = new Handler(); 
    private ImageRunnable imageRunnable = new ImageRunnable(); 
    private Paint paint; 
    private Canvas canvas; 
    private Matrix matrix; 
     
    /**圖片的坐標*/ 
    private float imageX, imageY; 
    /**獲取的圖片*/ 
    private Bitmap bmp; 
    /**圖片寬高*/ 
    private float bmpW, bmpH; 
    /**屏幕大小*/ 
    private int screenW, screenH; 
 
    /**
     * SurfaceView初始化函數
     */ 
    public ImageSurfaceView(Context context, AttributeSet attrs) { 
        super(context, attrs); 
        sfh = this.getHolder(); 
        sfh.addCallback(this); 
        paint = new Paint(); 
        paint.setColor(Color.WHITE); 
        paint.setAntiAlias(true); 
        setFocusable(true); 
    } 
    /**
     * SurfaceView視圖創建,響應此函數
     */ 
    @Override 
    public void surfaceCreated(SurfaceHolder holder) { 
        System.out.println("ImageSurfaceView is surfaceCreated"); 
        screenH = this.getHeight(); 
        screenW = this.getWidth(); 
                handler.post(imageRunnable); 
    } 
    /**
     * 遊戲繪圖
     */ 
    public void draw() { 
        try { 
            canvas = sfh.lockCanvas(); 
            canvas.drawRGB(0, 0, 0); 
            canvas.save(); 
            //繪制  
            canvas.drawBitmap(bmp, matrix, paint); 
            System.out.println("繪制圖像瞭嗎?"); 
            canvas.restore(); 
        } catch (Exception e) { 
            e.printStackTrace(); 
        } finally { 
            if (canvas != null) 
                sfh.unlockCanvasAndPost(canvas); 
        } 
    } 
    /**
     * 觸屏事件監聽
     */ 
    @Override 
    public boolean onTouchEvent(MotionEvent event) { 
        return true; 
    } 
     
    /**
     * 圖片的線程運行
     */ 
    class ImageRunnable implements Runnable{ 
        @Override 
        public void run() { 
            long start = System.currentTimeMillis(); 
            draw(); 
            long end = System.currentTimeMillis(); 
            if (end – start < 500) { 
                handler.postDelayed(this, 200 – (end-start)); 
            }else{ 
                handler.post(this); 
            } 
        } 
    } 
     
    /**
     * SurfaceView視圖狀態發生改變,響應此函數
     */ 
    @Override 
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { 
        System.out.println("ImageSurfaceView is surfaceChanged"); 
    } 
    /**
     * SurfaceView視圖消亡時,響應此函數
     */ 
    @Override 
    public void surfaceDestroyed(SurfaceHolder holder) { 
        System.out.println("ImageSurfaceView is surfaceDestroyed"); 
    } 

public class ImageSurfaceView extends SurfaceView implements Callback{
 //用於控制SurfaceView
 private SurfaceHolder sfh;
 private Handler handler = new Handler();
 private ImageRunnable imageRunnable = new ImageRunnable();
 private Paint paint;
 private Canvas canvas;
 private Matrix matrix;
 
 /**圖片的坐標*/
 private float imageX, imageY;
 /**獲取的圖片*/
 private Bitmap bmp;
 /**圖片寬高*/
 private float bmpW, bmpH;
 /**屏幕大小*/
 private int screenW, screenH;

 /**
  * SurfaceView初始化函數
  */
 public ImageSurfaceView(Context context, AttributeSet attrs) {
  super(context, attrs);
  sfh = this.getHolder();
  sfh.addCallback(this);
  paint = new Paint();
  paint.setColor(Color.WHITE);
  paint.setAntiAlias(true);
  setFocusable(true);
 }
 /**
  * SurfaceView視圖創建,響應此函數
  */
 @Override
 public void surfaceCreated(SurfaceHolder holder) {
  System.out.println("ImageSurfaceView is surfaceCreated");
  screenH = this.getHeight();
  screenW = this.getWidth();
                handler.post(imageRunnable);
 }
 /**
  * 遊戲繪圖
  */
 public void draw() {
  try {
   canvas = sfh.lockCanvas();
   canvas.drawRGB(0, 0, 0);
   canvas.save();
   //繪制
   canvas.drawBitmap(bmp, matrix, paint);
   System.out.println("繪制圖像瞭嗎?");
   canvas.restore();
  } catch (Exception e) {
   e.printStackTrace();
  } finally {
   if (canvas != null)
    sfh.unlockCanvasAndPost(canvas);
  }
 }
 /**
  * 觸屏事件監聽
  */
 @Override
 public boolean onTouchEvent(MotionEvent event) {
  return true;
 }
 
 /**
  * 圖片的線程運行
  */
 class ImageRunnable implements Runnable{
  @Override
  public void run() {
   long start = System.currentTimeMillis();
   draw();
   long end = System.currentTimeMillis();
   if (end – start < 500) {
    handler.postDelayed(this, 200 – (end-start));
   }else{
    handler.post(this);
   }
  }
 }
 
 /**
  * SurfaceView視圖狀態發生改變,響應此函數
  */
 @Override
 public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
  System.out.println("ImageSurfaceView is surfaceChanged");
 }
 /**
  * SurfaceView視圖消亡時,響應此函數
  */
 @Override
 public void surfaceDestroyed(SurfaceHolder holder) {
  System.out.println("ImageSurfaceView is surfaceDestroyed");
 }
}

 

layout的xml代碼如下(使用方法,類的全地址做為控件名):

[java]
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent" 
    > 
     
    <akai.test.getImage.ImageSurfaceView android:id="@+id/myImageView" 
        android:layout_width="fill_parent" 
        android:layout_height="fill_parent" 
        /> 
     
    <LinearLayout android:id="@+id/buttons" 
        android:layout_width="fill_parent" 
        android:layout_height="wrap_content" 
        android:orientation="horizontal" 
        android:background="@android:color/white" 
        > 
        <Button android:id="@+id/getImage" 
            android:layout_width="wrap_content" 
            android:layout_height="wrap_content" 
            android:text="選擇圖片" 
            /> 
        <Button android:id="@+id/getImage_ok" 
            android:layout_width="wrap_content" 
            android:layout_height="wrap_content" 
            android:text="確定" 
            /> 
        <Button android:id="@+id/getImage_cancle" 
            android:layout_width="wrap_content" 
            android:layout_height="wrap_content" 
            android:text="取消" 
            /> 
    </LinearLayout> 
     
</FrameLayout> 
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
   
    <akai.test.getImage.ImageSurfaceView android:id="@+id/myImageView"
        android:layout_width="fill_parent"
     android:layout_height="fill_parent"
     />
   
    <LinearLayout android:id="@+id/buttons"
        android:layout_width="fill_parent"
     android:layout_height="wrap_content"
     android:orientation="horizontal"
     android:background="@android:color/white"
     >
     <Button android:id="@+id/getImage"
         android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="選擇圖片"
         />
     <Button android:id="@+id/getImage_ok"
         android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="確定"
         />
     <Button android:id="@+id/getImage_cancle"
         android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="取消"
         />
    </LinearLayout>
   
</FrameLayout>

 

以上代碼為例子,僅供參考!

 

註意以下問題:

1、本類的初始化函數需要加入參數,為:public ImageSurfaceView(Context context, AttributeSet attrs) ;

2、不要在初始化的時候獲取screen的寬度和高度,在初始化的時候並還沒有執行SurfaceCreated,所以獲取寬度和高度要在surfaceCreated或者之後,且在surfaceDestroyed之前;

3、在顯示本控件的時候,會執行surfaceCreated和surfaceChanged,當跳轉到其他界面的時候則執行surfaceDestroyed(不管是否當前的activity已經銷毀),所以如果在跳轉回到次控件的時候立刻執行sfh.lockCanvas()的話將會獲得空值Null。

 摘自 阿凱的專欄

發佈留言