Android getWindowVisibleDisplayFrame() [轉(zhuǎn)載]

獲取窗口可視區(qū)域大小: getWindowVisibleDisplayFrame() 是View類下的一個方法厚棵,從方法的名字就可以看出吧寺,它是用來獲取當(dāng)前窗口可視區(qū)域大小的涛酗。

此方法的原型為

/**
     * Retrieve the overall visible display size in which the window this view is
     * attached to has been positioned in.  This takes into account screen
     * decorations above the window, for both cases where the window itself
     * is being position inside of them or the window is being placed under
     * then and covered insets are used for the window to position its content
     * inside.  In effect, this tells you the available area where content can
     * be placed and remain visible to users.
     *
     * <p>This function requires an IPC back to the window manager to retrieve
     * the requested information, so should not be used in performance critical
     * code like drawing.
     *
     * @param outRect Filled in with the visible display frame.  If the view
     * is not attached to a window, this is simply the raw display size.
     */
public void getWindowVisibleDisplayFrame(Rect outRect);

它接受一個Rect對象作為參數(shù),執(zhí)行過程中會根據(jù)當(dāng)前窗口可視區(qū)域大小更新outRect的值,執(zhí)行完畢后量九,就可以根據(jù)更新后的outRect來確定窗口可視區(qū)域的大小。所以正如outRect的名字所見颂碧,它是一個輸出參數(shù)荠列,后面如果提到getWindowVisibleDisplayFrame()方法的返回結(jié)果,指的也是參數(shù)outRect更新后的結(jié)果载城,getWindowVisibleDisplayFrame()本身是沒有返回值的肌似。此外,由于是輸出參數(shù)诉瓦,outRect必須不為null川队,一般在使用前會先new一個沒有大小的Rect對象力细,將其作為參數(shù)傳給getWindowVisibleDisplayFrame()方法

Rect rect = new Rect();
view.getWindowVisibleDisplayFrame(rect);

由于getWindowVisibleDisplayFrame()方法是View類下的一個方法,所以只能通過View對象來調(diào)用固额。一個窗口中通常都會有多個View眠蚂,getWindowVisibleDisplayFrame()方法的返回結(jié)果和該窗口中選取的View并沒有關(guān)系。在某個時刻斗躏,使用當(dāng)前窗口中的任意View執(zhí)行g(shù)etWindowVisibleDisplayFrame()返回的結(jié)果都是一樣的逝慧。這也很容易理解,getWindowVisibleDisplayFrame()方法返回的是窗口的可視區(qū)域大小啄糙,并非某個View的可視區(qū)域大小笛臣,所以用窗口中的任意View來執(zhí)行都是沒有差別的。一般來說可以使用當(dāng)前窗口的根View來執(zhí)行這個方法隧饼,也就是調(diào)用Window對象的getDecorView().getWindowVisibleDisplayFrame()來獲取沈堡。在Acitivity和Dialog中可以用getWindow()來得到Window對象,合起來就是這樣的燕雁。

Rect rect = new Rect();
getWindow().getDecorView().getWindowVisibleDisplayFrame(rect);

這里需要注意的是踱蛀,由于getWindowVisibleDisplayFrame()方法是用來獲取某個窗口的可視區(qū)域大小,所以調(diào)用getWindowVisibleDisplayFrame()方法的View必須包含在該窗口中贵白,如果是一個孤立的View率拒,或者包含在其他窗口中,是沒有意義的禁荒。例如

Rect rect = new Rect();
// 這個new出來的View并沒有add到任何窗口上猬膨,所以調(diào)用它的getWindowVisibleDisplayFrame()方法是沒有意義的。
new View(this).getWindowVisibleDisplayFrame(rect);

雖然getWindowVisibleDisplayFrame()的執(zhí)行結(jié)果和窗口中View的選取沒有關(guān)系呛伴,但是卻和執(zhí)行此方法時View的狀態(tài)有關(guān)勃痴。由于此方法是用來獲取窗口的可視區(qū)域大小,所以如果調(diào)用此方法時热康,調(diào)用的View對象還沒有附著(attach)到任何Window上沛申,那么執(zhí)行此方法將不會得到實際的某個窗口的可視區(qū)域大小,只有View對象已經(jīng)attach到Window上之后姐军,調(diào)用此方法才能得到真實的窗口的可視區(qū)域大小铁材。當(dāng)調(diào)用的View對象還沒有attach到Window時,getWindowVisibleDisplayFrame()方法會估計出一個可能的可視區(qū)域大小奕锌,這個大小通常是設(shè)備的屏幕尺寸(以像素為單位)著觉,由于它并不代表真實的窗口可視區(qū)域大小,所以這個數(shù)值的意義不大惊暴。

由于在Activity/Fragment/Dialog的onCreate()方法中饼丘,View對象還沒有attach到Window上,所以在onCreate()方法中執(zhí)行某個View的getWindowVisibleDisplayFrame()方法辽话,是不會得到當(dāng)前Window實際的可視區(qū)域大小的肄鸽。

在Activity的onAttachedToWindow()方法中執(zhí)行g(shù)etWindowVisibleDisplayFrame()卫病,也是得不到當(dāng)前Window實際的可視區(qū)域大小的。因為Activity的onAttachedToWindow()方法執(zhí)行時典徘,表示當(dāng)前Window被attach到window manager中忽肛,Window中的View仍然沒有attach到Window上。

View attach到Window之后烂斋,View對象的onAttachedToWindow()方法會被執(zhí)行屹逛,理論上來說,在自定義View的onAttachedToWindow()方法中執(zhí)行g(shù)etWindowVisibleDisplayFrame()應(yīng)該可以得到當(dāng)前Window實際的可視區(qū)域大小汛骂,但實際情況卻并非如此罕模。在自定義View的onAttachedToWindow()方法中執(zhí)行g(shù)etWindowVisibleDisplayFrame()會概率性的出現(xiàn)不同的結(jié)果,有時返回的rect對象大小是0帘瞭,有時則是設(shè)備的屏幕尺寸淑掌,但都不是當(dāng)前Window實際的可視區(qū)域大小。具體原因未知蝶念,沒有仔細(xì)研究抛腕。所以,也不要在View對象的onAttachedToWindow()方法中執(zhí)行g(shù)etWindowVisibleDisplayFrame()媒殉。

要想得到當(dāng)前Window實際的可視區(qū)域大小担敌,可以在Activity/Fragment/Dialog的onWindowFocusChanged()方法中執(zhí)行g(shù)etWindowVisibleDisplayFrame()。這時Window中的View對象都已經(jīng)attach到Window上廷蓉。

還有一點需要說明的是全封,getWindowVisibleDisplayFrame()的執(zhí)行結(jié)果和View是否可見沒有關(guān)系。View無論是VISIBLE桃犬,還是INVISIBLE或者GONE刹悴,對getWindowVisibleDisplayFrame()的執(zhí)行結(jié)果沒有影響。當(dāng)View是INVISIBLE的時候攒暇,其onDraw()方法不會被調(diào)用土匀,當(dāng)View是GONE的時候,其onDraw()和onLayout()方法不會被調(diào)用形用。但無論是INVISIBLE或者GONE就轧,onAttachedToWindow()都會被調(diào)用,也就是說View會被attach到Window上尾序,所以即使View是INVISIBLE或者GONE的钓丰,getWindowVisibleDisplayFrame()也能夠正確的返回。

getWindowVisibleDisplayFrame()的執(zhí)行結(jié)果分析

這里所說的getWindowVisibleDisplayFrame()執(zhí)行結(jié)果均是指當(dāng)前Window實際的可視區(qū)域大小每币,對調(diào)用的View對象還沒有attach到Window時,getWindowVisibleDisplayFrame()方法估計出可視區(qū)域大小的情況不做討論琢歇。

getWindowVisibleDisplayFrame()執(zhí)行結(jié)果和以下因素有關(guān)

  1. 系統(tǒng)狀態(tài)欄

系統(tǒng)狀態(tài)欄會影響getWindowVisibleDisplayFrame()執(zhí)行結(jié)果outRect中的top屬性的值兰怠。
如果窗口是全屏的梦鉴,也就是設(shè)置了flags為WindowManager.LayoutParams.FLAG_FULLSCREEN,或者Android:windowFullscreen設(shè)置為true揭保,則outRect中的top屬性不受狀態(tài)欄影響肥橙,其值始終為0。否則秸侣,outRect中的top屬性值將會受到系統(tǒng)狀態(tài)欄的影響存筏。
如果窗口的LayoutParams的height設(shè)置為WindowManager.LayoutParams.MATCH_PARENT,則outRect中的top值會等于系統(tǒng)狀態(tài)欄的高度味榛,如果窗口的LayoutParams的height設(shè)置為WindowManager.LayoutParams.WRAP_CONTENT或者某個具體的值椭坚,則outRect中的top值會等于系統(tǒng)狀態(tài)欄和窗口重疊區(qū)域的高度,如果沒有重疊搏色,則是0善茎。
例如,屏幕高度為1920频轿,窗口高度設(shè)置為1900垂涯,窗口居中顯示。這時窗口上下距離屏幕各有10個像素的距離航邢。假如系統(tǒng)狀態(tài)欄高度為60耕赘,窗口和狀態(tài)欄的重疊區(qū)域的高度就是50。因此膳殷,getWindowVisibleDisplayFrame()返回的outRect中的top值為50鞠苟。

Paste_Image.png

上面這幾點可以歸結(jié)為一點,outRect中的top值等于系統(tǒng)狀態(tài)欄在理論上會對窗口上方所在位置產(chǎn)生的影響秽之。

如果窗口是全屏的当娱,系統(tǒng)狀態(tài)欄將無法影響窗口上方位置,因此考榨,outRect中的top值始終為0跨细。如果窗口的LayoutParams的height設(shè)置為WindowManager.LayoutParams.MATCH_PARENT,則理論上窗口將到達(dá)屏幕最上方的位置河质,但是由于狀態(tài)欄的存在冀惭,會壓迫窗口位置到狀態(tài)欄下方,因此掀鹅,outRect中的top值等于系統(tǒng)狀態(tài)欄的高度散休。如果窗口的LayoutParams的height設(shè)置為WindowManager.LayoutParams.WRAP_CONTENT或者某個具體的值,且窗口和狀態(tài)欄存在重疊乐尊,則這時狀態(tài)欄同樣會試圖壓迫窗口位置到狀態(tài)欄下方戚丸,其位移就是重疊區(qū)域的高度,因此outRect中的top值等于重疊區(qū)域的高度扔嵌。需要注意的是限府,這里狀態(tài)欄對窗口位置的影響并不會實際生效夺颤,也就是窗口仍然會和狀態(tài)欄重疊,因此狀態(tài)欄對窗口位置的影響是一種理論上的胁勺,并非一定會生效世澜。

  1. 虛擬鍵盤
    虛擬鍵盤會影響getWindowVisibleDisplayFrame()執(zhí)行結(jié)果outRect中的bottom屬性的值。

如果虛擬鍵盤是隱藏的署穗,則outRect中的bottom屬性的值將始終等于屏幕高度(實際上還要減去虛擬按鍵欄的高度寥裂,這里先忽略虛擬按鍵)。如果虛擬鍵盤是顯示的案疲,outRect中的bottom屬性的值將等于屏幕高度減去理論上虛擬鍵盤會對窗口位置產(chǎn)生的影響封恰。如果窗口高度是MATCH_PARENT的,則outRect中的bottom屬性的值將等于屏幕高度減去虛擬鍵盤的高度络拌。

同樣的例子俭驮,屏幕高度為1920,窗口高度設(shè)置為1900春贸,窗口居中顯示混萝。這時窗口上下距離屏幕各有10個像素的距離。假如虛擬鍵盤高度為600萍恕,窗口和虛擬鍵盤的重疊區(qū)域的高度就是590逸嘀。因此,getWindowVisibleDisplayFrame()返回的outRect中的bottom值為1920 - 590允粤。

  1. 虛擬按鍵欄

虛擬按鍵欄會影響getWindowVisibleDisplayFrame()執(zhí)行結(jié)果outRect中的bottom屬性的值崭倘。

這里只考慮軟鍵盤是隱藏的情況,如果軟鍵盤是顯示的类垫,則軟鍵盤和虛擬按鍵欄對outRect中的bottom屬性的值的影響將會疊加司光。

如果虛擬按鍵欄是隱藏的,則outRect中的bottom屬性的值將始終等于屏幕高度悉患。如果虛擬按鍵是顯示的残家,outRect中的bottom屬性的值將等于屏幕高度減去理論上虛擬按鍵會對窗口位置產(chǎn)生的影響。如果窗口高度是MATCH_PARENT的售躁,則outRect中的bottom屬性的值將等于屏幕高度減去虛擬按鍵的高度坞淮。

這里不再舉例說明。

綜上所述陪捷,getWindowVisibleDisplayFrame()執(zhí)行結(jié)果會受到系統(tǒng)狀態(tài)欄回窘,系統(tǒng)軟鍵盤,系統(tǒng)虛擬按鍵的影響市袖。

這里需要注意的是啡直,getWindowVisibleDisplayFrame()的結(jié)果并不是該窗口實際的大小(雖然它和窗口的大小有一定關(guān)系)。例如一個居中顯示的對話框付枫,它的實際高度只有500px烹玉,它和系統(tǒng)狀態(tài)欄驰怎,系統(tǒng)軟鍵盤阐滩,系統(tǒng)虛擬按鍵欄都沒有重疊,那么getWindowVisibleDisplayFrame()的結(jié)果就是設(shè)備的尺寸大小县忌,而不是該對話框的實際大小掂榔。

此外,雖然方法名字中有一個Visible症杏,但是getWindowVisibleDisplayFrame()的結(jié)果并不受該窗口是否在被其他窗口遮擋的影響装获。即使該窗口已經(jīng)被切換到后臺,只要該窗口還沒有dettach厉颤,getWindowVisibleDisplayFrame()的結(jié)果就不會變化穴豫。

getWindowVisibleDisplayFrame()的應(yīng)用

android系統(tǒng)中,并沒有提供api來獲取系統(tǒng)狀態(tài)欄逼友,系統(tǒng)軟鍵盤和系統(tǒng)虛擬按鍵欄的高度精肃,但在應(yīng)用中有時會需要獲取這幾個數(shù)值。由于getWindowVisibleDisplayFrame()返回結(jié)果會受到系統(tǒng)狀態(tài)欄帜乞,系統(tǒng)軟鍵盤司抱,系統(tǒng)虛擬按鍵的影響。因此黎烈,這個api常常被用來獲取系統(tǒng)狀態(tài)欄习柠,系統(tǒng)軟鍵盤和系統(tǒng)虛擬按鍵欄的高度。
對系統(tǒng)狀態(tài)欄高度照棋,獲取一個非全屏资溃,且窗口的LayoutParams的height設(shè)置為WindowManager.LayoutParams.MATCH_PARENT的窗口可視區(qū)域大小,其top值就是狀態(tài)欄的高度烈炭。
對系統(tǒng)軟鍵盤溶锭,獲取一個高度是MATCH_PARENT的窗口在軟鍵盤顯示和隱藏兩種不同狀態(tài)下的可視區(qū)域大小,將bottom值相減就可以得到軟鍵盤的高度梳庆。
對系統(tǒng)系統(tǒng)虛擬按鍵欄暖途,獲取一個高度是MATCH_PARENT的窗口在虛擬按鍵顯示和隱藏兩種不同狀態(tài)下的可視區(qū)域大小,將bottom值相減就可以得到虛擬按鍵的高度膏执。

getWindowVisibleDisplayFrame()的性能問題

在getWindowVisibleDisplayFrame()方法的注釋中有這樣一段

Paste_Image.png

說明getWindowVisibleDisplayFrame()方法是通過IPC方式從window manager中獲取到這個信息的驻售,相對來說它的開銷會比較大,因此不適合放在對性能要求很高的地方調(diào)用更米,例如View繪制的代碼中欺栗。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子迟几,更是在濱河造成了極大的恐慌消请,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,640評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件类腮,死亡現(xiàn)場離奇詭異臊泰,居然都是意外死亡,警方通過查閱死者的電腦和手機蚜枢,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,254評論 3 395
  • 文/潘曉璐 我一進店門缸逃,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人厂抽,你說我怎么就攤上這事需频。” “怎么了筷凤?”我有些...
    開封第一講書人閱讀 165,011評論 0 355
  • 文/不壞的土叔 我叫張陵昭殉,是天一觀的道長。 經(jīng)常有香客問我藐守,道長挪丢,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,755評論 1 294
  • 正文 為了忘掉前任吗伤,我火速辦了婚禮吃靠,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘足淆。我一直安慰自己巢块,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,774評論 6 392
  • 文/花漫 我一把揭開白布巧号。 她就那樣靜靜地躺著族奢,像睡著了一般。 火紅的嫁衣襯著肌膚如雪丹鸿。 梳的紋絲不亂的頭發(fā)上越走,一...
    開封第一講書人閱讀 51,610評論 1 305
  • 那天,我揣著相機與錄音靠欢,去河邊找鬼廊敌。 笑死,一個胖子當(dāng)著我的面吹牛门怪,可吹牛的內(nèi)容都是我干的骡澈。 我是一名探鬼主播,決...
    沈念sama閱讀 40,352評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼掷空,長吁一口氣:“原來是場噩夢啊……” “哼肋殴!你這毒婦竟也來了囤锉?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,257評論 0 276
  • 序言:老撾萬榮一對情侶失蹤护锤,失蹤者是張志新(化名)和其女友劉穎官地,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體烙懦,經(jīng)...
    沈念sama閱讀 45,717評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡驱入,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,894評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了修陡。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片沧侥。...
    茶點故事閱讀 40,021評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡可霎,死狀恐怖魄鸦,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情癣朗,我是刑警寧澤拾因,帶...
    沈念sama閱讀 35,735評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站旷余,受9級特大地震影響绢记,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜正卧,卻給世界環(huán)境...
    茶點故事閱讀 41,354評論 3 330
  • 文/蒙蒙 一蠢熄、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧炉旷,春花似錦签孔、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,936評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至罐盔,卻和暖如春但绕,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背惶看。 一陣腳步聲響...
    開封第一講書人閱讀 33,054評論 1 270
  • 我被黑心中介騙來泰國打工捏顺, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人纬黎。 一個月前我還...
    沈念sama閱讀 48,224評論 3 371
  • 正文 我出身青樓幅骄,卻偏偏與公主長得像,于是被迫代替她去往敵國和親莹桅。 傳聞我的和親對象是個殘疾皇子昌执,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,974評論 2 355

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

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,160評論 25 707
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫烛亦、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,105評論 4 62
  • 我想要抱抱的時候懂拾,你能伸出手把我摟進懷里煤禽; 我想要親親的時候,你把軟軟的嘴唇貼到我軟軟的臉上岖赋; 我肚子疼的時候檬果,你...
    陽光下的小麥小姐閱讀 221評論 0 0
  • 畢業(yè)后進入SN选脊,與三個小伙伴玩的很好,經(jīng)常約在出租屋里一邊涮火鍋脸甘,一邊聊公司八卦恳啥,個人情感,談天說地丹诀,無所不聊钝的。 ...
    傲霜Sissi閱讀 419評論 0 0
  • 昨晚匆匆從武漢趕回來,一路上連晚飯都沒能顧得上吃铆遭,全靠幾塊奧利奧撐著硝桩,好在路程不遠(yuǎn)基本上挺得過去。百無聊賴之際枚荣,我...
    夏野閱讀 94評論 0 0