為了分析Window的工作機(jī)制崎岂,我們需要先了解如何使用WindowManager添加一個(gè)Window篡诽,下面的代碼演示了通過WindowManager添加Window的過程
Button mFloatingButton =new Button(this);
mFloatingButton.setText("button");
int type = WindowManager.LayoutParams.TYPE_TOAST;
int flags = WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
WindowManager.LayoutParams mLayoutParams = new
WindowManager.LayoutParams(WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,type ,flags , PixelFormat.TRANSPARENT);
mLayoutParams.gravity = Gravity.LEFT|Gravity.TOP;
mLayoutParams.x = 100;
mLayoutParams.y = 300;
WindowManager mWindowManager = this.getWindowManager();
mWindowManager.addView(mFloatingButton,mLayoutParams);
上述代碼可以將一個(gè)Button添加到屏幕坐標(biāo)為(100,300)的位置上犁苏。WindowManager.LayoutParams中的flags和type這兩個(gè)參數(shù)比較重要联喘,下面對(duì)其進(jìn)行說明。
Flags參數(shù)表示W(wǎng)indow的屬性驳棱,它有很多選項(xiàng)逗载,通過這些選項(xiàng)可以控制Window的顯示特性哆窿,這里介紹幾個(gè)常用的選項(xiàng):
- FLAG_NOT_FOCUSABLE
表示W(wǎng)indow不需要獲取焦點(diǎn),也不需要接收各種輸入事件厉斟,此標(biāo)記會(huì)同時(shí)啟用FLAG_NOT_TOUCH_MODAL,最終事件會(huì)直接傳遞給下層的具有焦點(diǎn)的Window挚躯。- FLAG_NOT_TOUCH_MODAL
系統(tǒng)會(huì)將當(dāng)前Window區(qū)域以外的單擊事件傳遞給底層的Window,當(dāng)前Window區(qū)域內(nèi)的單擊事件則自己處理擦秽。這個(gè)標(biāo)記很重要码荔,一般來說都需要開啟此標(biāo)記漩勤。否則其他Window將無法收到單擊事件。- FLAG_SHOW_WHEN_LOCKED
開啟此模式可以讓W(xué)indow顯示在鎖屏的界面上缩搅。
Type參數(shù)表示W(wǎng)indow的類型越败,Window有三種類型,分別是應(yīng)用Window硼瓣、子Window和系統(tǒng)Window究飞。應(yīng)用類Window對(duì)應(yīng)一個(gè)Activity。子Window不能單獨(dú)存在堂鲤,它需要附屬在特定的父Window之中亿傅,比如常見的一些Dialog就是一個(gè)子Window。系統(tǒng)Window是需要聲明權(quán)限在能創(chuàng)建的Window瘟栖,比如Toast和系統(tǒng)狀態(tài)欄這些都是系統(tǒng)Window葵擎。
Window是分層的,每個(gè)Window都有對(duì)應(yīng)的z-ordered慢宗,層級(jí)大的會(huì)覆蓋在層級(jí)小的Window的上面坪蚁,這和HTML中的z-index的概念是完全一致的。在三類Window中镜沽,應(yīng)用Window的層級(jí)范圍是199,子Window的層級(jí)范圍是10001999,系統(tǒng)Window的層級(jí)范圍是2000~2999贱田,這些層級(jí)范圍對(duì)應(yīng)著WindowManager.LayoutParams的type參數(shù)缅茉。如果想要Window位于所有Window的最頂層,那么采用較大的層級(jí)即可男摧。很顯然系統(tǒng)Window的層級(jí)是最大的蔬墩,而且系統(tǒng)層級(jí)有很多值,一般我們可以選用TYPE_SYSTEM_OVERLAY或者TYPE_SYSTEM_ERROR,如果 采用TYPE_SYSTEM_ERROR耗拓,只需要為type參數(shù)指定這個(gè)層級(jí)即可:mLayoutParams.type = LayoutParams.TYPE_SYSTEM_ERROR拇颅;同時(shí)聲明權(quán)限:<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW“>。
因?yàn)橄到y(tǒng)類型的Window是需要檢查權(quán)限的乔询,如果不在AndroidManifest中使用相應(yīng)的權(quán)限樟插,那么創(chuàng)建Window的時(shí)候就會(huì)報(bào)錯(cuò)。
WindowManager所提供的功能很簡(jiǎn)單竿刁,常用的只要三個(gè)方法 黄锤,即添加View、更新View和刪除View,這三個(gè)方法定義在ViewManager中食拜,而WindowManager繼承了ViewManager鸵熟。
public interface ViewManager{
public void addView(View view, ViewGroup.LayoutParams params);
public void updateViewLayout(View view, ViewGroup.LayoutParams params);
public void removeView(View view);
}
Window是一個(gè)抽象概念,每一個(gè)Window都對(duì)應(yīng)著一個(gè)View和一個(gè)ViewRootImpl,Window和View通過ViewRootImpl來建立聯(lián)系负甸,因此Window并不是實(shí)際存在的流强,它是以View的是形式存在痹届。這點(diǎn)可以從WindowManager的定義中看出來,它提供的三個(gè)接口方法addView打月、updateViewLayout以及removeView都是針對(duì)View的队腐,這說明View才是Window存在的實(shí)體,有視圖的地方就有Window僵控,比如Activity香到、Dialog、Toast报破,除此之外悠就,還有一些依托Window而實(shí)現(xiàn)的視圖,比如PopUpWindow充易、菜單梗脾。在實(shí)際使用中無法直接訪問Window,必須通過WindowManager。