Android P下WindowManager與LayoutParams的詳解

在上一篇《AndroidP下SystemUI的啓動與定製化》中,瞭解了SystemUI的啓動流程,同時也知道流程的最後主要是StatusBar經過WindowManager的addView()將view裝載在系統的界面上,在此以前都要利用WindowManager.LayoutParams來設置該window的顯示,那麼在源碼裏出現的WindowManager是什麼?WindowManager.LayoutParams的參數又有什麼特色?下文就將從這兩個方面來分析WindowManager。html

1、WindowManager是什麼?

1.1 WindowManager與window的關係

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進行更新。函數

1.2 WindowManager對象的獲取

當咱們想要在界面上添加一個子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
... ...

2、WindowManager.LayoutParams參數解析

2.1 構造函數

在第一節裏面提到過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)

對於具體的參數詳情在下面一一介紹。

2.2 Type

第二個構造函數裏包含了一個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替代。

2.3 Flags

第三個構造函數中參數多了一個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)代替。

2.4 Format

在第四個構造函數中多了一個int型format參數,這個參數則表示window所需的位圖格式,默認爲OPAQUE,也有多是PixelFormat中的一種,另外setColorMode(int)的使用可能會覆蓋格式的選擇。

2.5 w、h

第五個構造函數中多了兩個int型的w,h,w就是表示該window的width,h則是height,能夠是具體數值,也能夠是LayoutParams.MATCH_PARENT,LayoutParams.WRAP_CONTENT。

2.6 xpos、ypos

在第六個構造函數中多了兩個int型xpos和ypos,其中xpos表示該window的橫座標位置,ypos爲縱座標位置。

也就是咱們常見的 LayoutParams.x 和LayoutParams.y。

2.7 Gravity

根據Gravity設置window在屏幕中的位置,例如Gravity.BOTTOM表示放置在容器的底部,Gravity.CENTER_HORIZONTAL表示放置在容器的水平中心,Gravity.CENTER則表示放置在容器的中心,固然還有其餘的類型,能夠根據本身的需求,設置Gravity的位置。

2.8 token

token是一個Binder代理對象,表示window的一個令牌,WMS會檢測傳入的token是否能夠添加到系統上,通常來講,系統會爲咱們自動添加token。

2.9 softInputMode

該屬性是表示設置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得到焦點時,始終顯示任何軟輸入區域。

3、總結

以上爲WindowManager和LayoutParams 的介紹,官方文檔中對於他們的介紹有點晦澀難懂,上面一部分就轉換爲了平常說法。在實際項目開發中,咱們有時候須要自定義一個window,那麼就要設置該window的顯示模式和類型,這就須要理清楚LayoutParams 每一個屬性的含義,以應用至多變的需求當中。上面所述大都包含了平常開發中所用到的設置,其它可參照官方文檔

參考資料:

官方文檔

我的博客:

fuusy.github.io/

相關文章
相關標籤/搜索