2012年6月27日 星期三

float window for android

最近在練習寫一些Android app, 在網路上看到浮動視窗的例子.
自己試了一下, 效果還不錯, 可以拿來作一些外掛功能的選單.

記錄一下關鍵的地方, 範例如下:
public class WindowParam extends Application {
 private WindowManager.LayoutParams wmParams=new WindowManager.LayoutParams();
 private Activity refActivity = null;
 
 public WindowManager.LayoutParams getMywmParams(){
  return wmParams;
 }
}

public class TestActivity extends Activity {
 ......
 private void onCreate() {
     try { 
      WindowManager wm = (WindowManager)mContext.getSystemService("window");     
      WindowParam wmParams = ((WindowParam)mContext.getApplicationContext()).getMywmParams();
      wmParams.width=width;
      wmParams.height=height;
      wmParams.x=0;
      wmParams.y=0;
      wmParams.type=LayoutParams.TYPE_PHONE;
      wmParams.flags=LayoutParams.FLAG_NOT_TOUCH_MODAL | LayoutParams.FLAG_NOT_FOCUSABLE;
      wmParams.format=PixelFormat.RGBA_8888;
      wmParams.gravity=Gravity.LEFT|Gravity.TOP;
      
      btn = new MyFloatView(mContext);
      wm.addView(btn, wmParams);
      
     } catch (Exception e) {
   Log.d("shaw error", e.toString());
  }
     
 }
 ......
}

public class MyFloatView extends TextView {
    private float mTouchStartX;
    private float mTouchStartY;
    private float x;
    private float y;
    
    private WindowManager wm=(WindowManager)getContext().getApplicationContext().getSystemService("window");
    private WindowManager.LayoutParams wmParams = ((MyApplication)getContext().getApplicationContext()).getMywmParams();

    public MyFloatView(Context context) {
        super(context);        
        // TODO Auto-generated constructor stub
    }
    
     @Override
     public boolean onTouchEvent(MotionEvent event) {         
         x = event.getRawX();
         y = event.getRawY()-25;
         Log.i("currP", "currX"+x+"====currY"+y);
         switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mTouchStartX =  event.getX();  
                mTouchStartY =  event.getY();               
                Log.i("startP", "startX"+mTouchStartX+"====startY"+mTouchStartY);                
                break;
            case MotionEvent.ACTION_MOVE:
                updateViewPosition();
                break;
            case MotionEvent.ACTION_UP:
                updateViewPosition();
                mTouchStartX=mTouchStartY=0;
                break;
            }
            return true;
        }     
     private void updateViewPosition(){
        wmParams.x=(int)( x-mTouchStartX);
        wmParams.y=(int) (y-mTouchStartY);
        wm.updateViewLayout(this, wmParams);
     }
}


要注意的地方:
1. wmParams需建立global物件或正確傳遞, 在更新畫面時必須填入完整的wmParams, 否則會出現大大的icon擋住視窗, 網路上查到的作法大多都是用global object來進行傳遞.

2. wmParams.type=LayoutParams.TYPE_PHONE; 決定這個視窗在整個system的顯示等級. 可以參考官網的WindowManager.LayoutParams. 數字愈小表示priority愈大, 

3. y = event.getRawY()-25; 這個25是status bar的高度, 依各家手機之解析度不同, 這東西的值也不同. 必須去動態取得. 這個值會影響touch的效果, 如果你所在的畫面有status bar, 但沒減去正確的offset, 系統在render畫面時, 物件的Y值就會錯誤.

4. manifest的 user-permission 要加入 android.permission.SYSTEM_ALERT_WINDOW

1 則留言:

Che An 提到...

您好,我最近也有用到float window的需求,請問是否有您參考的sample code網站方便讓我研究,謝謝您。