SystemUI(二)WindowManager與LayoutParams的解析

在上一篇《# SystemUI(一)基于Android9.0SystemUI的啟動(dòng)與定制化
》中,了解了SystemUI的啟動(dòng)流程,同時(shí)也知道流程的最后主要是StatusBar通過(guò)WindowManager的addView()將view裝載在系統(tǒng)的界面上,在此之前都要利用WindowManager.LayoutParams來(lái)設(shè)置該window的顯示,那么在源碼里出現(xiàn)的WindowManager是什么?WindowManager.LayoutParams的參數(shù)又有什么特點(diǎn)?下文就將從這兩個(gè)方面來(lái)分析WindowManager。

一、WindowManager是什么?

1.1 WindowManager與window的關(guān)系

WindowManager是什么?官方對(duì)于它的解釋只有這么一句話(huà)

The interface that apps use to talk to the window manager.

翻譯過(guò)來(lái)就是app與window通信的一個(gè)接口。從語(yǔ)義上看WindowManager是用來(lái)管理window的一個(gè)接口,那么window又是什么?其實(shí)我們常見(jiàn)的Dialog、Popup、StatusBar等本質(zhì)就是window,window是一個(gè)抽象類(lèi),相當(dāng)于一個(gè)聯(lián)盟,Dialog、Popup等view只有依附在window這個(gè)聯(lián)盟才能發(fā)揮功能,而WindowManager就像是聯(lián)盟的會(huì)長(zhǎng),負(fù)責(zé)與子view等會(huì)員通信,并且能夠?qū)λ麄冞M(jìn)行增加、更新和刪除(WindowManager是一個(gè)接口,具體的操作是在WindowManagerImpl實(shí)現(xiàn)類(lèi)中)。

WindowManager繼承自ViewManager,ViewManager是用于向Activity添加和刪除子視圖的接口,在官方文檔上顯示ViewManager中有三個(gè)抽象方法:

第一個(gè)addView():表示通過(guò)LayoutParams將參數(shù)傳遞給view,然后將view添加到window上。也就是我們平常在系統(tǒng)界面上添加自定義Popup、Dialog、菜單等。

第二個(gè)removeView():表示將window上的view刪除。

第三個(gè)updateViewLayout():表示將view進(jìn)行更新。

1.2 WindowManager對(duì)象的獲取

當(dāng)我們想要在界面上添加一個(gè)子view就需要調(diào)用WindowManager的addView(),那么如何獲取WindowManager的實(shí)例呢?文檔中給出了這樣一個(gè)方法:

可以知道方法中參數(shù)name的不同,將獲取不同的對(duì)象。name為WINDOW_SERVICE時(shí),即Context.getSystemService(Context.WINDOW_SERVICE) 返回WindowManager對(duì)象。除此之外以下列舉出比較常見(jiàn)的name所對(duì)應(yīng)的對(duì)象。

name object
POWER_SERVICE PowerManager
ALARM_SERVICE AlarmManager
NOTIFICATION_SERVICE NotificationManager
ACTIVITY_SERVICE ActivityManager
LAYOUT_INFLATER_SERVICE LayoutInflater
LOCATION_SERVICE LocationManager
WIFI_SERVICE WifiManager
... ...

二、WindowManager.LayoutParams參數(shù)解析

2.1 構(gòu)造函數(shù)

在第一節(jié)里面提到過(guò)addView(View view, ViewGroup.LayoutParams params)是通過(guò)LayoutParams將參數(shù)傳遞給view,然后將view添加到window上。LayoutParams表示包含了layout寬高,位置,類(lèi)型等信息,通過(guò)設(shè)置這些信息,生成不同的view。

addView()中的第二個(gè)參數(shù)ViewGroup.LayoutParams是WindowManager.LayoutParams的父類(lèi),我們具體來(lái)看看WindowManager.LayoutParams。

WindowManager.LayoutParams有下面7種構(gòu)造函數(shù):

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)

對(duì)于具體的參數(shù)詳情在下面一一介紹。

2.2 Type

第二個(gè)構(gòu)造函數(shù)里包含了一個(gè)int 型的type,而type代表的是不同類(lèi)型的window,window分為三種類(lèi)型:

  • Application windows(應(yīng)用程序window)

    層級(jí)范圍為1-99,是屬于正常的頂級(jí)應(yīng)用程序window,例如我們所見(jiàn)到的Activity。

  • Sub-windows(子window)

    層級(jí)范圍為1000-1999,例如部分Dialog。

  • System windows (系統(tǒng)window)

    層級(jí)范圍為2000-2999,是屬于最高層級(jí),例如StatusBar,NavigationBar,覆蓋在所有window之上。

而在這三種類(lèi)型下又分為了很多不同的狀態(tài),官方文檔上介紹了多種type,這里就介紹幾種常見(jiàn)且重要的type。

  • TYPE_APPLICATION_OVERLAY

    覆蓋于所有activity window之上,但低于關(guān)鍵系統(tǒng)window(如狀態(tài)欄,IME等),系統(tǒng)可以隨時(shí)改變這些窗口的位置,大小或可見(jiàn)性,并且需要申請(qǐng)Manifest.permission.SYSTEM_ALERT_WINDOW權(quán)限。

  • TYPE_STATUS_BAR

    表示狀態(tài)欄,系統(tǒng)只有一個(gè)狀態(tài)欄窗口,它位于屏幕的頂部,所有其他窗口都向下移動(dòng),當(dāng)我們想要替換成自己自定義的StatusBar時(shí),可設(shè)置type為它。

  • TYPE_SEARCH_BAR

    搜索欄,系統(tǒng)只有一個(gè)搜索欄窗口并且位于屏幕頂部。

  • TYPE_KEYGUARD_DIALOG

    鍵盤(pán)鎖顯示的對(duì)話(huà)框。

注意 :TYPE_TOAST、TYPE_SYSTEM_OVERLAY、TYPE_SYSTEM_ERROR、TYPE_SYSTEM_ALERT、TYPE_PRIORITY_PHONE、TYPE_PHONE這幾個(gè)type在API 26中已經(jīng)廢棄,由TYPE_APPLICATION_OVERLAY替代。

2.3 Flags

第三個(gè)構(gòu)造函數(shù)中參數(shù)多了一個(gè)int型的Flags,其表示window的屬性,下面就介紹幾種常見(jiàn)的Flag。

  • 默認(rèn)狀態(tài)不設(shè)置Flag
    在默認(rèn)不設(shè)置Flag的狀態(tài)下,在新window層級(jí)下的window將接受不到任何touch事件,即使是在新window的范圍外。

  • FLAG_NOT_FOCUSABLE
    表示此窗口范圍內(nèi)的事件自己處理,范圍外的事件依舊為原窗口處理;例如點(diǎn)擊該窗口外的view,依然會(huì)有響應(yīng)。另外只要設(shè)置了此Flag,都將會(huì)啟用FLAG_NOT_TOUCH_MODAL,最后,設(shè)置了該Flag就表示window不會(huì)與輸入方法交互,例如該window上有EditView,點(diǎn)擊EditView是不會(huì)彈出軟鍵盤(pán)的。

  • FLAG_NOT_TOUCH_MODAL
    表示即使window是處于上面的默認(rèn)狀態(tài)下,設(shè)置了該Flag,新window范圍外的view也是可以響應(yīng)touch事件。

  • FLAG_NOT_TOUCHABLE
    表示該window將不會(huì)接受任何touch事件,例如點(diǎn)擊該window,不會(huì)有響應(yīng),只會(huì)傳給下面有聚焦的窗口。

  • FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS

    表示負(fù)責(zé)繪制系統(tǒng)欄背景。如果設(shè)置,系統(tǒng)欄將以透明背景繪制,此窗口中的相應(yīng)區(qū)域?qū)⑻畛鋀indow#getStatusBarColor()和Window#getNavigationBarColor()中指定的顏色。

  • FLAG_FULLSCREEN

    表示顯示此window時(shí)隱藏所有屏幕裝飾(包括狀態(tài)欄)

  • FLAG_FORCE_NOT_FULLSCREEN

    表示比FLAG_FULLSCREEN低一級(jí),會(huì)顯示狀態(tài)欄

  • FLAG_SHOW_WALLPAPER

    表示要求系統(tǒng)壁紙顯示在該window后面,window表面必須是半透明的,才能真正看到它背后的壁紙

  • FLAG_SHOW_WHEN_LOCKED

    表示window顯示在鎖屏的的界面上。此標(biāo)志在API27中已廢棄,使用R.attr.showWhenLocked或Activity.setShowWhenLocked(boolean)代替。

2.4 Format

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

2.5 w、h

第五個(gè)構(gòu)造函數(shù)中多了兩個(gè)int型的w,h,w就是表示該window的width,h則是height,可以是具體數(shù)值,也可以是LayoutParams.MATCH_PARENT,LayoutParams.WRAP_CONTENT。

2.6 xpos、ypos

在第六個(gè)構(gòu)造函數(shù)中多了兩個(gè)int型xpos和ypos,其中xpos表示該window的橫坐標(biāo)位置,ypos為縱坐標(biāo)位置。

也就是我們常見(jiàn)的 LayoutParams.x 和LayoutParams.y。

2.7 Gravity

根據(jù)Gravity設(shè)置window在屏幕中的位置,例如Gravity.BOTTOM表示放置在容器的底部,Gravity.CENTER_HORIZONTAL表示放置在容器的水平中心,Gravity.CENTER則表示放置在容器的中心,當(dāng)然還有其他的類(lèi)型,可以根據(jù)自己的需求,設(shè)置Gravity的位置。

2.8 token

token是一個(gè)Binder代理對(duì)象,表示window的一個(gè)令牌,WMS會(huì)檢測(cè)傳入的token是否可以添加到系統(tǒng)上,一般來(lái)說(shuō),系統(tǒng)會(huì)為我們自動(dòng)添加token。

2.9 softInputMode

該屬性是表示設(shè)置window軟鍵盤(pán)輸入?yún)^(qū)域的顯示模式,例如我們有時(shí)候會(huì)發(fā)現(xiàn)window的軟鍵盤(pán)打開(kāi)會(huì)占據(jù)整個(gè)屏幕,遮擋了后面的視圖,這時(shí)候就可以設(shè)置這個(gè)屬性,調(diào)整軟鍵盤(pán)合適的樣式。

例如以下幾種:

  • SOFT_INPUT_ADJUST_NOTHING

    將不會(huì)調(diào)整大小,直接覆蓋在window上。

  • SOFT_INPUT_ADJUST_PAN

    具有輸入方法的window可以平移,例如有兩個(gè)EditView的輸入框,一個(gè)為Ev1,一個(gè)為Ev2,當(dāng)你點(diǎn)擊Ev1想要輸入數(shù)據(jù)時(shí),當(dāng)前的Ev1的輸入框會(huì)移到軟鍵盤(pán)上方,軟件盤(pán)是跟在Ev1的下面,保證Ev1是可見(jiàn)的,Ev2則不一定可見(jiàn)。

    另外該模式不能與SOFT_INPUT_ADJUST_RESIZE結(jié)合使用。

  • SOFT_INPUT_ADJUST_RESIZE

    整個(gè)window會(huì)平移調(diào)整大小,例如點(diǎn)擊一個(gè)EditView,整個(gè)layout都將平移可見(jiàn)且處于軟件盤(pán)的上方。

    同樣的該模式不能與SOFT_INPUT_ADJUST_PAN結(jié)合使用;另外如果窗口的布局參數(shù)標(biāo)志包含F(xiàn)LAG_FULLSCREEN,則將忽略這個(gè)值,窗口不會(huì)調(diào)整大小,但會(huì)保持全屏。

  • SOFT_INPUT_ADJUST_UNSPECIFIED

    不指明,系統(tǒng)根據(jù)內(nèi)容自動(dòng)設(shè)置該模式和還是其他模式。

  • SOFT_INPUT_MASK_ADJUST

    window會(huì)調(diào)整大小以適應(yīng)軟鍵盤(pán)窗口。

  • SOFT_INPUT_STATE_ALWAYS_HIDDEN

    當(dāng)此window獲得焦點(diǎn)時(shí),始終隱藏任何軟輸入?yún)^(qū)域。

  • SOFT_INPUT_STATE_ALWAYS_VISIBLE

    當(dāng)此window獲得焦點(diǎn)時(shí),始終顯示任何軟輸入?yún)^(qū)域。

三、總結(jié)

以上為WindowManager和LayoutParams 的介紹,官方文檔中對(duì)于他們的介紹有點(diǎn)晦澀難懂,上面一部分就轉(zhuǎn)換為了日常說(shuō)法。在實(shí)際項(xiàng)目開(kāi)發(fā)中,我們有時(shí)候需要自定義一個(gè)window,那么就要設(shè)置該window的顯示模式和類(lèi)型,這就需要理清楚LayoutParams 每個(gè)屬性的含義,以應(yīng)用至多變的需求當(dāng)中。上面所述大都包含了日常開(kāi)發(fā)中所用到的設(shè)置,其它可參照官方文檔

參考資料:

官方文檔

個(gè)人博客:

https://fuusy.github.io/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,406評(píng)論 6 538
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,034評(píng)論 3 423
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 177,413評(píng)論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀(guān)的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 63,449評(píng)論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,165評(píng)論 6 410
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 55,559評(píng)論 1 325
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,606評(píng)論 3 444
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 42,781評(píng)論 0 289
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,327評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,084評(píng)論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,278評(píng)論 1 371
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,849評(píng)論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,495評(píng)論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 34,927評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 36,172評(píng)論 1 291
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,010評(píng)論 3 396
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,241評(píng)論 2 375

推薦閱讀更多精彩內(nèi)容