Window表示一個窗口的概念,在某些特殊的時候,比如你需要在桌面或者鎖屏上顯示一些類似懸浮窗的東西時候就需要用到Window。Window是一個抽象類,Window的實現類是PhoneWindow。Window的具體實現位於WindowManagerService中,WindowManager和WindowManagerService的交互是一個IPC過程。Android中所有的視圖都是通過Window來呈現的,不管是Activity、Dialog還是Toast,他們的視圖實際上都是附加在Window上的。
一個懸浮窗的例子
點擊Button按鈕,將一個ImageView添加到座標爲(100,300)的位置上,並且可以隨手拖動的。
代碼塊
public class TestActivity extends Activity implements OnTouchListener {
private static final String TAG = “TestActivity”;
private Button mCreateWindowButton;
private ImageView mImageView;
private WindowManager.LayoutParams mLayoutParams;
private WindowManager mWindowManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
initView();
}
private void initView() {
mCreateWindowButton = (Button) findViewById(R.id.button1);
mWindowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
}
public void onButtonClick(View v) {
if (v == mCreateWindowButton) {
mImageView = new ImageView(this);
mImageView.setBackgroundResource(R.drawable.ic_launcher);
mLayoutParams = new WindowManager.LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, 0, 0,
PixelFormat.TRANSPARENT);
mLayoutParams.flags = LayoutParams.FLAG_NOT_TOUCH_MODAL
| LayoutParams.FLAG_NOT_FOCUSABLE
| LayoutParams.FLAG_SHOW_WHEN_LOCKED;
mLayoutParams.type = LayoutParams.TYPE_SYSTEM_ERROR;
mLayoutParams.gravity = Gravity.TOP | Gravity.LEFT;
mLayoutParams.x = 100;
mLayoutParams.y = 300;
mImageView.setOnTouchListener(this);
mWindowManager.addView(mImageView, mLayoutParams);
}
}
@Override
public boolean onTouch(View v, MotionEvent event) {
int rawX = (int) event.getRawX();
int rawY = (int) event.getRawY();
int x = (int) event.getX();
int y = (int) event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: {
break;
}
case MotionEvent.ACTION_MOVE: {
Log.d(TAG, "onTouch: rawX " + rawX);
Log.d(TAG, "onTouch: rawY " + rawY);
mLayoutParams.x = rawX;
mLayoutParams.y = rawY;
mWindowManager.updateViewLayout(mImageView, mLayoutParams);
break;
}
case MotionEvent.ACTION_UP: {
break;
}
default:
break;
}
return false;
}
@Override
protected void onDestroy() {
try {
mWindowManager.removeView(mImageView);
} catch (IllegalArgumentException e) {
e.printStackTrace();
}
super.onDestroy();
}
}
WindowManager.LayoutParams的Flag和Type
FLAG
FLAG_NOT_FOCUSABLE,當前Window不獲取焦點,也不接收各種輸入事件,會同時啓用FLAG_NOT_TOUCH_MODAL,事件會傳遞給下層具有焦點的Window。
FLAG_NOT_TOUCH_MODAL,當前Window區域外的單擊事件傳遞給底層,區域內的單擊事件自己處理,一般都需要開啓。
FLAG_SHOW_WHEN_LOCKED,可以讓Window顯示在鎖屏界面上。
Type
Type表示Window的類型,有應用Window、子Window和系統Window。
應用Window,一般對應一個Activity。層級範圍1~99。
子Window,不能單獨存在,需要特定的父Window,比如一般的Dialog。層級範圍1000~1999。
系統Window,需要權限聲明,比如Toast。層級範圍2000~2999。
一般可以選用WindowManager.LayoutParams.TYPE_SYSTEM_ERROR或者TYPE_SYSTEM_OVERLAY同時聲明權限。使用WindowManager.LayoutParams.TYPE_SYSTEM_ERROR時,同時聲明
注
Window並不實際存在,以View的形式存在。每個Window對應着一個View和ViewRootImpl,Window和View通過ViewRootImpl建立聯繫。所以在實際使用中其實我們並不能訪問到真正的Window,而只能通過WindowManager。
WindowManager常用的三個功能:addView,updateViewLayout,removeView
別忘了onDestory()中的mWindowManager.removeView(mImageView)