在上一篇《# 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ì)于它的解釋只有這么一句話
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è)抽象類,相當(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)類中)邑闲。
WindowManager繼承自ViewManager,ViewManager是用于向Activity添加和刪除子視圖的接口梧油,在官方文檔上顯示ViewManager中有三個(gè)抽象方法:
- abstract void addView(View view, ViewGroup.LayoutParams params)
- abstract void removeView(View view)
- abstract void updateViewLayout(View view, ViewGroup.LayoutParams params)
第一個(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寬高,位置紧唱,類型等信息活尊,通過(guò)設(shè)置這些信息,生成不同的view漏益。
addView()中的第二個(gè)參數(shù)ViewGroup.LayoutParams是WindowManager.LayoutParams的父類蛹锰,我們具體來(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代表的是不同類型的window,window分為三種類型:
-
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之上转捕。
而在這三種類型下又分為了很多不同的狀態(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ì)話框。
注意 :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)然還有其他的類型,可以根據(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的顯示模式和類型,這就需要理清楚LayoutParams 每個(gè)屬性的含義软舌,以應(yīng)用至多變的需求當(dāng)中才漆。上面所述大都包含了日常開(kāi)發(fā)中所用到的設(shè)置,其它可參照官方文檔 佛点。
參考資料:
個(gè)人博客: