1. 程式人生 > >Android獲取視窗可視區域大小: getWindowVisibleDisplayFrame()

Android獲取視窗可視區域大小: getWindowVisibleDisplayFrame()

getWindowVisibleDisplayFrame()方法

getWindowVisibleDisplayFrame()是View類下的一個方法,從方法的名字就可以看出,它是用來獲取當前視窗可視區域大小的。

此方法的原型為

public void getWindowVisibleDisplayFrame(Rect outRect);

它接受一個Rect物件作為引數,執行過程中會根據當前視窗可視區域大小更新outRect的值,執行完畢後,就可以根據更新後的outRect來確定視窗可視區域的大小。所以正如outRect的名字所見,它是一個輸出引數,後面如果提到getWindowVisibleDisplayFrame()方法的返回結果,指的也是引數outRect更新後的結果,getWindowVisibleDisplayFrame()本身是沒有返回值的。此外,由於是輸出引數,outRect必須不為null,一般在使用前會先new一個沒有大小的Rect物件,將其作為引數傳給getWindowVisibleDisplayFrame()方法。

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

getWindowVisibleDisplayFrame()的執行結果和View物件選取的關係

由於getWindowVisibleDisplayFrame()方法是View類下的一個方法,所以只能通過View物件來呼叫。一個視窗中通常都會有多個View,getWindowVisibleDisplayFrame()方法的返回結果和該視窗中選取的View並沒有關係。在某個時刻,使用當前視窗中的任意View執行getWindowVisibleDisplayFrame()返回的結果都是一樣的。這也很容易理解,getWindowVisibleDisplayFrame()方法返回的是視窗的可視區域大小,並非某個View的可視區域大小,所以用視窗中的任意View來執行都是沒有差別的。一般來說可以使用當前視窗的根View來執行這個方法,也就是呼叫Window物件的getDecorView().getWindowVisibleDisplayFrame()來獲取。在Acitivity和Dialog中可以用getWindow()來得到Window物件,合起來就是這樣的。

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

這裡需要注意的是,由於getWindowVisibleDisplayFrame()方法是用來獲取某個視窗的可視區域大小,所以呼叫getWindowVisibleDisplayFrame()方法的View必須包含在該視窗中,如果是一個孤立的View,或者包含在其他視窗中,是沒有意義的。例如

Rect rect = new Rect();
// 這個new出來的View並沒有add到任何視窗上,所以呼叫它的getWindowVisibleDisplayFrame()方法是沒有意義的。
new View(this).getWindowVisibleDisplayFrame(rect);

getWindowVisibleDisplayFrame()的執行結果和View物件狀態的關係

雖然getWindowVisibleDisplayFrame()的執行結果和視窗中View的選取沒有關係,但是卻和執行此方法時View的狀態有關。由於此方法是用來獲取視窗的可視區域大小,所以如果呼叫此方法時,呼叫的View物件還沒有附著(attach)到任何Window上,那麼執行此方法將不會得到實際的某個視窗的可視區域大小,只有View物件已經attach到Window上之後,呼叫此方法才能得到真實的視窗的可視區域大小。當呼叫的View物件還沒有attach到Window時,getWindowVisibleDisplayFrame()方法會估計出一個可能的可視區域大小,這個大小通常是裝置的螢幕尺寸(以畫素為單位),由於它並不代表真實的視窗可視區域大小,所以這個數值的意義不大。

由於在Activity/Fragment/Dialog的onCreate()方法中,View物件還沒有attach到Window上,所以在onCreate()方法中執行某個View的getWindowVisibleDisplayFrame()方法,是不會得到當前Window實際的可視區域大小的。

在Activity的onAttachedToWindow()方法中執行getWindowVisibleDisplayFrame(),也是得不到當前Window實際的可視區域大小的。因為Activity的onAttachedToWindow()方法執行時,表示當前Window被attach到window manager中,Window中的View仍然沒有attach到Window上。

View attach到Window之後,View物件的onAttachedToWindow()方法會被執行,理論上來說,在自定義View的onAttachedToWindow()方法中執行getWindowVisibleDisplayFrame()應該可以得到當前Window實際的可視區域大小,但實際情況卻並非如此。在自定義View的onAttachedToWindow()方法中執行getWindowVisibleDisplayFrame()會概率性的出現不同的結果,有時返回的rect物件大小是0,有時則是裝置的螢幕尺寸,但都不是當前Window實際的可視區域大小。具體原因未知,沒有仔細研究。所以,也不要在View物件的onAttachedToWindow()方法中執行getWindowVisibleDisplayFrame()。

要想得到當前Window實際的可視區域大小,可以在Activity/Fragment/Dialog的onWindowFocusChanged()方法中執行getWindowVisibleDisplayFrame()。這時Window中的View物件都已經attach到Window上。

還有一點需要說明的是,getWindowVisibleDisplayFrame()的執行結果和View是否可見沒有關係。View無論是VISIBLE,還是INVISIBLE或者GONE,對getWindowVisibleDisplayFrame()的執行結果沒有影響。當View是INVISIBLE的時候,其onDraw()方法不會被呼叫,當View是GONE的時候,其onDraw()和onLayout()方法不會被呼叫。但無論是INVISIBLE或者GONE,onAttachedToWindow()都會被呼叫,也就是說View會被attach到Window上,所以即使View是INVISIBLE或者GONE的,getWindowVisibleDisplayFrame()也能夠正確的返回。

getWindowVisibleDisplayFrame()的執行結果分析

這裡所說的getWindowVisibleDisplayFrame()執行結果均是指當前Window實際的可視區域大小,對呼叫的View物件還沒有attach到Window時,getWindowVisibleDisplayFrame()方法估計出可視區域大小的情況不做討論。

getWindowVisibleDisplayFrame()執行結果和以下因素有關

  1. 系統狀態列

    系統狀態列會影響getWindowVisibleDisplayFrame()執行結果outRect中的top屬性的值。

    如果視窗是全屏的,也就是設定了flags為WindowManager.LayoutParams.FLAG_FULLSCREEN,或者android:windowFullscreen設定為true,則outRect中的top屬性不受狀態列影響,其值始終為0。否則,outRect中的top屬性值將會受到系統狀態列的影響。

    如果視窗的LayoutParams的height設定為WindowManager.LayoutParams.MATCH_PARENT,則outRect中的top值會等於系統狀態列的高度,如果視窗的LayoutParams的height設定為WindowManager.LayoutParams.WRAP_CONTENT或者某個具體的值,則outRect中的top值會等於系統狀態列和視窗重疊區域的高度,如果沒有重疊,則是0。

    例如,螢幕高度為1920,視窗高度設定為1900,視窗居中顯示。這時視窗上下距離螢幕各有10個畫素的距離。假如系統狀態列高度為60,視窗和狀態列的重疊區域的高度就是50。因此,getWindowVisibleDisplayFrame()返回的outRect中的top值為50。

    這裡寫圖片描述

    上面這幾點可以歸結為一點,outRect中的top值等於系統狀態列在理論上會對視窗上方所在位置產生的影響。

    如果視窗是全屏的,系統狀態列將無法影響視窗上方位置,因此,outRect中的top值始終為0。如果視窗的LayoutParams的height設定為WindowManager.LayoutParams.MATCH_PARENT,則理論上視窗將到達螢幕最上方的位置,但是由於狀態列的存在,會壓迫視窗位置到狀態列下方,因此,outRect中的top值等於系統狀態列的高度。如果視窗的LayoutParams的height設定為WindowManager.LayoutParams.WRAP_CONTENT或者某個具體的值,且視窗和狀態列存在重疊,則這時狀態列同樣會試圖壓迫視窗位置到狀態列下方,其位移就是重疊區域的高度,因此outRect中的top值等於重疊區域的高度。需要注意的是,這裡狀態列對視窗位置的影響並不會實際生效,也就是視窗仍然會和狀態列重疊,因此狀態列對視窗位置的影響是一種理論上的,並非一定會生效。

  2. 虛擬鍵盤

    虛擬鍵盤會影響getWindowVisibleDisplayFrame()執行結果outRect中的bottom屬性的值。

    如果虛擬鍵盤是隱藏的,則outRect中的bottom屬性的值將始終等於螢幕高度(實際上還要減去虛擬按鍵欄的高度,這裡先忽略虛擬按鍵)。如果虛擬鍵盤是顯示的,outRect中的bottom屬性的值將等於螢幕高度減去理論上虛擬鍵盤會對視窗位置產生的影響。如果視窗高度是MATCH_PARENT的,則outRect中的bottom屬性的值將等於螢幕高度減去虛擬鍵盤的高度。

    同樣的例子,螢幕高度為1920,視窗高度設定為1900,視窗居中顯示。這時視窗上下距離螢幕各有10個畫素的距離。假如虛擬鍵盤高度為600,視窗和虛擬鍵盤的重疊區域的高度就是590。因此,getWindowVisibleDisplayFrame()返回的outRect中的bottom值為1920 - 590。

  3. 虛擬按鍵欄

    虛擬按鍵欄會影響getWindowVisibleDisplayFrame()執行結果outRect中的bottom屬性的值。

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

    如果虛擬按鍵欄是隱藏的,則outRect中的bottom屬性的值將始終等於螢幕高度。如果虛擬按鍵是顯示的,outRect中的bottom屬性的值將等於螢幕高度減去理論上虛擬按鍵會對視窗位置產生的影響。如果視窗高度是MATCH_PARENT的,則outRect中的bottom屬性的值將等於螢幕高度減去虛擬按鍵的高度。

    這裡不再舉例說明。

綜上所述,getWindowVisibleDisplayFrame()執行結果會受到系統狀態列,系統軟鍵盤,系統虛擬按鍵的影響。

這裡需要注意的是,getWindowVisibleDisplayFrame()的結果並不是該視窗實際的大小(雖然它和視窗的大小有一定關係)。例如一個居中顯示的對話方塊,它的實際高度只有500px,它和系統狀態列,系統軟鍵盤,系統虛擬按鍵欄都沒有重疊,那麼getWindowVisibleDisplayFrame()的結果就是裝置的尺寸大小,而不是該對話方塊的實際大小。

此外,雖然方法名字中有一個Visible,但是getWindowVisibleDisplayFrame()的結果並不受該視窗是否在被其他視窗遮擋的影響。即使該視窗已經被切換到後臺,只要該視窗還沒有dettach,getWindowVisibleDisplayFrame()的結果就不會變化。

getWindowVisibleDisplayFrame()的應用

在Android系統中,並沒有提供api來獲取系統狀態列,系統軟鍵盤和系統虛擬按鍵欄的高度,但在應用中有時會需要獲取這幾個數值。由於getWindowVisibleDisplayFrame()返回結果會受到系統狀態列,系統軟鍵盤,系統虛擬按鍵的影響。因此,這個api常常被用來獲取系統狀態列,系統軟鍵盤和系統虛擬按鍵欄的高度。

對系統狀態列高度,獲取一個非全屏,且視窗的LayoutParams的height設定為WindowManager.LayoutParams.MATCH_PARENT的視窗可視區域大小,其top值就是狀態列的高度。

對系統軟鍵盤,獲取一個高度是MATCH_PARENT的視窗在軟鍵盤顯示和隱藏兩種不同狀態下的可視區域大小,將bottom值相減就可以得到軟鍵盤的高度。

對系統系統虛擬按鍵欄,獲取一個高度是MATCH_PARENT的視窗在虛擬按鍵顯示和隱藏兩種不同狀態下的可視區域大小,將bottom值相減就可以得到虛擬按鍵的高度。

getWindowVisibleDisplayFrame()的效能問題

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

這裡寫圖片描述

說明getWindowVisibleDisplayFrame()方法是通過IPC方式從window manager中獲取到這個資訊的,相對來說它的開銷會比較大,因此不適合放在對效能要求很高的地方呼叫,例如View繪製的程式碼中。

相關推薦

Android獲取視窗區域大小: getWindowVisibleDisplayFrame()

getWindowVisibleDisplayFrame()方法 getWindowVisibleDisplayFrame()是View類下的一個方法,從方法的名字就可以看出,它是用來獲取當前視窗可視區域大小的。 此方法的原型為 public void

Android 系統(49)---Android獲取視窗區域大小: getWindowVisibleDisplayFrame()

getWindowVisibleDisplayFrame()方法getWindowVisibleDisplayFrame()是View類下的一個方法,從方法的名字就可以看出,它是用來獲取當前視窗可視區域大小的。此方法的原型為public void getWindowVisibleDisplayFrame(Re

瀏覽器窗口區域大小

設置 ble safari tle containe ava 指定 lpad 內部 一:網頁可見區域寬高,不包括工具欄和滾動條(瀏覽器窗口可視區域大小) 1.對於IE9+、chrome、firefox、Opera、Safari: window.innerHeight瀏覽器窗

獲取視窗高度window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight

對於Internet Explorer、Chrome、Firefox、Opera 以及 Safari:  window.innerHeight – 瀏覽器視窗的內部高度  window.innerWidth – 瀏覽器視窗的內部寬度  對於 Internet Explo

MFC獲取視窗狀態的兩種API方法

嚴以律己,寬以待人. 三思而後行. GMail/GTalk: yanglinbo#google.com; MSN/Email: tx7do#yahoo.com.cn; QQ: 3 0 3 3 9 6 9 2 0 .

js獲取瀏覽器區域的寬度

   在沒有宣告DOCTYPE的IE中,瀏覽器顯示視窗大小隻能以下獲取: document.body.offsetWidth document.body.offsetHeight 在聲明瞭DOCTYPE的瀏覽器中,可以用以下來獲取瀏覽器顯示視窗大小: docume

獲取屏幕寬高度與區域寬高度(availWidth、clientWidth、width、innerWidth)

標簽欄 獲取 包含 cli 頂部 bsp ima img nbsp   經常會遇到需要獲取屏幕寬度、高度,可視區域寬度、高度等問題,也就常跟這幾個打交道,一不小心,還真愛弄混淆了。   先來列舉下這幾個吧:   screen.availHeight、screen.ava

jQuery中獲取文檔的高度、區域高度以及滾動條距頁面頂部的高度

doc 支持 document span ros p s margin window 窗口 在寫頁面的時候,經常會碰到這樣的情況,就是要獲取文檔的高度、可視區域高度或者滾動條距頁面頂部的高度等情況。 但我總是有些愛搞混淆了,這裏還是簡單做個筆記吧,這裏只限於使用jQuer

Nativescript Android Keyboard Open Overlay OR Push View(鍵盤開啟覆蓋檢視或推出區域

App_Resources/Android/src/main/AndroidManifest.xml <activity android:name="com.tns.NativeScriptActivity" android:windowSoftInputMode="adjus

滑鼠拖拽視窗效果(不允許拖出螢幕的區域

html樣式 <body> <div id="div1"></div> </body> css樣式 #div1 {

獲取區域高度賦值給div(解決document.body.clientHeight的返回值為0的問題)

設定html,body{height:100%} 在使用html5文件型別的時候, 設定了html body的高度100%之後,兩個瀏覽器就都能獲取document.body.clientHeight了 <!DOCTYPE html> <html> <head>

後臺文章編輯器的區域添加自定義功能按鈕

nload rac IT 樣式 admin lte size gist != 有時候我們需要自定義一些樣式或者功能,要麽就是直接在Text區域直接寫html代碼, 還有一種方法就是直接將自定義一些樣式或者功能添加到後臺文章編輯器的 可視區域。具體實現方式如下: 首先在對應的

後臺章編輯器區域沒有顯示樣式的解決方法

edi brush clas alt 方法 font 添加 nbsp png 使用後臺文章編輯器的時候,會當自定義class樣式在style.css時, 我們在文章編輯器加入class時,發現樣式並沒有顯示出來, 只有當在預覽頁面時才能看到樣式。 解決

js判斷元素是否在區域

comm scrolltop odi class screen lin 如果 set pre js部分: //監聽滾動條滑動距離 $(window).on('scroll', function(){ v

瀏覽器大小簡說(clientWidth,innerWidth)

ner ber eight style else alert height inner 寬度   網絡上獲取窗口文檔顯示區的寬高有以下三種方式:   1:window.innerHeight/innerWidth    第一種方式獲取的是可視區的寬高,包括了滾動條的寬度  

js滾動及區域的相關的操作

eight 可能 ins TP sof ron family client 祖先 element.getBoundingClientRect 判斷指定元素相對於頁面可視窗口的位置信息,通常結合windows.onScroll方法使用,當element.getBounding

6.2.25 BOM 屏幕的區域

charset bom client div scrip UNC tex log console <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <t

取不同瀏覽器區域寬高方法

new function family The port onos idt pac offset function getViewportOffset(){ if(window.innerWidth){ return { w:window.

區域載入圖片(懶載入應用)

// 可視區域載入 var aImages = document.images;//獲取圖片集合 loadImg(aImages); window.onscroll = function(){ loadImg(aIma

原生JS的(區域,向上滾動向下滾動兩種)圖片懶載入

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style>