在上一篇《AndroidP下SystemUI的啓動與定製化》中,瞭解了SystemUI的啓動流程,同時也知道流程的最後主要是StatusBar經過WindowManager的addView()將view裝載在系統的界面上,在此以前都要利用WindowManager.LayoutParams來設置該window的顯示,那麼在源碼裏出現的WindowManager是什麼?WindowManager.LayoutParams的參數又有什麼特色?下文就將從這兩個方面來分析WindowManager。html
WindowManager是什麼?官方對於它的解釋只有這麼一句話java
The interface that apps use to talk to the window manager.android
翻譯過來就是app與window通訊的一個接口。從語義上看WindowManager是用來管理window的一個接口,那麼window又是什麼?其實咱們常見的Dialog、Popup、StatusBar等本質就是window,window是一個抽象類,至關於一個聯盟,Dialog、Popup等view只有依附在window這個聯盟才能發揮功能,而WindowManager就像是聯盟的會長,負責與子view等會員通訊,而且可以對他們進行增長、更新和刪除(WindowManager是一個接口,具體的操做是在WindowManagerImpl實現類中)。git
WindowManager繼承自ViewManager,ViewManager是用於向Activity添加和刪除子視圖的接口,在官方文檔上顯示ViewManager中有三個抽象方法:github
第一個addView():表示經過LayoutParams將參數傳遞給view,而後將view添加到window上。也就是咱們日常在系統界面上添加自定義Popup、Dialog、菜單等。windows
第二個removeView():表示將window上的view刪除。app
第三個updateViewLayout():表示將view進行更新。函數
當咱們想要在界面上添加一個子view就須要調用WindowManager的addView(),那麼如何獲取WindowManager的實例呢?文檔中給出了這樣一個方法:佈局
能夠知道方法中參數name的不一樣,將獲取不一樣的對象。name爲WINDOW_SERVICE時,即Context.getSystemService(Context.WINDOW_SERVICE) 返回WindowManager對象。除此以外如下列舉出比較常見的name所對應的對象。post
name | object |
---|---|
POWER_SERVICE | PowerManager |
ALARM_SERVICE | AlarmManager |
NOTIFICATION_SERVICE | NotificationManager |
ACTIVITY_SERVICE | ActivityManager |
LAYOUT_INFLATER_SERVICE | LayoutInflater |
LOCATION_SERVICE | LocationManager |
WIFI_SERVICE | WifiManager |
... | ... |
在第一節裏面提到過addView(View view, ViewGroup.LayoutParams params)是經過LayoutParams將參數傳遞給view,而後將view添加到window上。LayoutParams表示包含了layout寬高,位置,類型等信息,經過設置這些信息,生成不一樣的view。
addView()中的第二個參數ViewGroup.LayoutParams是WindowManager.LayoutParams的父類,咱們具體來看看WindowManager.LayoutParams。
WindowManager.LayoutParams有下面7種構造函數:
Public constructors |
---|
1.WindowManager.LayoutParams() |
2.WindowManager.LayoutParams(int _type) |
3.WindowManager.LayoutParams(int _type, int _flags) |
4.WindowManager.LayoutParams(int _type, int _flags, int _format) |
5.WindowManager.LayoutParams(int w, int h, int _type, int _flags, int _format) |
6.WindowManager.LayoutParams(int w, int h, int xpos, int ypos, int _type, int _flags, int _format) |
7.WindowManager.LayoutParams(Parcel in) |
對於具體的參數詳情在下面一一介紹。
第二個構造函數裏包含了一個int 型的type,而type表明的是不一樣類型的window,window分爲三種類型:
Application windows(應用程序window)
層級範圍爲1-99,是屬於正常的頂級應用程序window,例如咱們所見到的Activity。
Sub-windows(子window)
層級範圍爲1000-1999,例如部分Dialog。
System windows (系統window)
層級範圍爲2000-2999,是屬於最高層級,例如StatusBar,NavigationBar,覆蓋在全部window之上。
而在這三種類型下又分爲了不少不一樣的狀態,官方文檔上介紹了多種type,這裏就介紹幾種常見且重要的type。
TYPE_APPLICATION_OVERLAY
覆蓋於全部activity window之上,但低於關鍵系統window(如狀態欄,IME等),系統能夠隨時改變這些窗口的位置,大小或可見性,而且須要申請Manifest.permission.SYSTEM_ALERT_WINDOW權限。
TYPE_STATUS_BAR
表示狀態欄,系統只有一個狀態欄窗口,它位於屏幕的頂部,全部其餘窗口都向下移動,當咱們想要替換成本身自定義的StatusBar時,可設置type爲它。
TYPE_SEARCH_BAR
搜索欄,系統只有一個搜索欄窗口而且位於屏幕頂部。
TYPE_KEYGUARD_DIALOG
鍵盤鎖顯示的對話框。
注意 :TYPE_TOAST、TYPE_SYSTEM_OVERLAY、TYPE_SYSTEM_ERROR、TYPE_SYSTEM_ALERT、TYPE_PRIORITY_PHONE、TYPE_PHONE這幾個type在API 26中已經廢棄,由TYPE_APPLICATION_OVERLAY替代。
第三個構造函數中參數多了一個int型的Flags,其表示window的屬性,下面就介紹幾種常見的Flag。
默認狀態不設置Flag 在默認不設置Flag的狀態下,在新window層級下的window將接受不到任何touch事件,即便是在新window的範圍外。
FLAG_NOT_FOCUSABLE 表示此窗口範圍內的事件本身處理,範圍外的事件依舊爲原窗口處理;例如點擊該窗口外的view,依然會有響應。另外只要設置了此Flag,都將會啓用FLAG_NOT_TOUCH_MODAL,最後,設置了該Flag就表示window不會與輸入方法交互,例如該window上有EditView,點擊EditView是不會彈出軟鍵盤的。
FLAG_NOT_TOUCH_MODAL 表示即便window是處於上面的默認狀態下,設置了該Flag,新window範圍外的view也是能夠響應touch事件。
FLAG_NOT_TOUCHABLE 表示該window將不會接受任何touch事件,例如點擊該window,不會有響應,只會傳給下面有聚焦的窗口。
FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS
表示負責繪製系統欄背景。若是設置,系統欄將以透明背景繪製,此窗口中的相應區域將填充Window#getStatusBarColor()和Window#getNavigationBarColor()中指定的顏色。
FLAG_FULLSCREEN
表示顯示此window時隱藏全部屏幕裝飾(包括狀態欄)
FLAG_FORCE_NOT_FULLSCREEN
表示比FLAG_FULLSCREEN低一級,會顯示狀態欄
FLAG_SHOW_WALLPAPER
表示要求系統壁紙顯示在該window後面,window表面必須是半透明的,才能真正看到它背後的壁紙
FLAG_SHOW_WHEN_LOCKED
表示window顯示在鎖屏的的界面上。此標誌在API27中已廢棄,使用R.attr.showWhenLocked或Activity.setShowWhenLocked(boolean)代替。
在第四個構造函數中多了一個int型format參數,這個參數則表示window所需的位圖格式,默認爲OPAQUE,也有多是PixelFormat中的一種,另外setColorMode(int)的使用可能會覆蓋格式的選擇。
第五個構造函數中多了兩個int型的w,h,w就是表示該window的width,h則是height,能夠是具體數值,也能夠是LayoutParams.MATCH_PARENT,LayoutParams.WRAP_CONTENT。
在第六個構造函數中多了兩個int型xpos和ypos,其中xpos表示該window的橫座標位置,ypos爲縱座標位置。
也就是咱們常見的 LayoutParams.x 和LayoutParams.y。
根據Gravity設置window在屏幕中的位置,例如Gravity.BOTTOM表示放置在容器的底部,Gravity.CENTER_HORIZONTAL表示放置在容器的水平中心,Gravity.CENTER則表示放置在容器的中心,固然還有其餘的類型,能夠根據本身的需求,設置Gravity的位置。
token是一個Binder代理對象,表示window的一個令牌,WMS會檢測傳入的token是否能夠添加到系統上,通常來講,系統會爲咱們自動添加token。
該屬性是表示設置window軟鍵盤輸入區域的顯示模式,例如咱們有時候會發現window的軟鍵盤打開會佔據整個屏幕,遮擋了後面的視圖,這時候就能夠設置這個屬性,調整軟鍵盤合適的樣式。
例如如下幾種:
SOFT_INPUT_ADJUST_NOTHING
將不會調整大小,直接覆蓋在window上。
SOFT_INPUT_ADJUST_PAN
具備輸入方法的window能夠平移,例若有兩個EditView的輸入框,一個爲Ev1,一個爲Ev2,當你點擊Ev1想要輸入數據時,當前的Ev1的輸入框會移到軟鍵盤上方,軟件盤是跟在Ev1的下面,保證Ev1是可見的,Ev2則不必定可見。
另外該模式不能與SOFT_INPUT_ADJUST_RESIZE結合使用。
SOFT_INPUT_ADJUST_RESIZE
整個window會平移調整大小,例如點擊一個EditView,整個layout都將平移可見且處於軟件盤的上方。
一樣的該模式不能與SOFT_INPUT_ADJUST_PAN結合使用;另外若是窗口的佈局參數標誌包含FLAG_FULLSCREEN,則將忽略這個值,窗口不會調整大小,但會保持全屏。
SOFT_INPUT_ADJUST_UNSPECIFIED
不指明,系統根據內容自動設置該模式和仍是其餘模式。
SOFT_INPUT_MASK_ADJUST
window會調整大小以適應軟鍵盤窗口。
SOFT_INPUT_STATE_ALWAYS_HIDDEN
當此window得到焦點時,始終隱藏任何軟輸入區域。
SOFT_INPUT_STATE_ALWAYS_VISIBLE
當此window得到焦點時,始終顯示任何軟輸入區域。
以上爲WindowManager和LayoutParams 的介紹,官方文檔中對於他們的介紹有點晦澀難懂,上面一部分就轉換爲了平常說法。在實際項目開發中,咱們有時候須要自定義一個window,那麼就要設置該window的顯示模式和類型,這就須要理清楚LayoutParams 每一個屬性的含義,以應用至多變的需求當中。上面所述大都包含了平常開發中所用到的設置,其它可參照官方文檔 。
參考資料:
我的博客: