getWindowVisibleDisplayFrame()方法

getWindowVisibleDisplayFrame()是View类下的一个方法,从方法的名字就可以看出,它是用来获取当前窗口可视区域大小的。就是contentParentView +actionbar的高度

此方法的原型为

public void getWindowVisibleDisplayFrame(Rect outRect);
  • 1

它接受一个Rect对象作为参数,执行过程中会根据当前窗口可视区域大小更新outRect的值,执行完毕后,就可以根据更新后的outRect来确定窗口可视区域的大小。所以正如outRect的名字所见,它是一个输出参数,后面如果提到getWindowVisibleDisplayFrame()方法的返回结果,指的也是参数outRect更新后的结果,getWindowVisibleDisplayFrame()本身是没有返回值的。此外,由于是输出参数,outRect必须不为null,一般在使用前会先new一个没有大小的Rect对象,将其作为参数传给getWindowVisibleDisplayFrame()方法。

Rect rect = new Rect();
view.getWindowVisibleDisplayFrame(rect);
  • 1
  • 2

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);
  • 1
  • 2

这里需要注意的是,由于getWindowVisibleDisplayFrame()方法是用来获取某个窗口的可视区域大小,所以调用getWindowVisibleDisplayFrame()方法的View必须包含在该窗口中,如果是一个孤立的View,或者包含在其他窗口中,是没有意义的。例如

Rect rect = new Rect();
// 这个new出来的View并没有add到任何窗口上,所以调用它的getWindowVisibleDisplayFrame()方法是没有意义的。
new View(this).getWindowVisibleDisplayFrame(rect);
  • 1
  • 2
  • 3

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()的更多相关文章

  1. Javascript进阶篇——(DOM—节点---获取浏览器窗口可视区域大小+获取网页尺寸)—笔记整理

    浏览器窗口可视区域大小获得浏览器窗口的尺寸(浏览器的视口,不包括工具栏和滚动条)的方法:一.对于IE9+.Chrome.Firefox.Opera 以及 Safari: • window.innerH ...

  2. JavaScript--DOM浏览器窗口可视区域大小

    浏览器窗口可视区域大小 获得浏览器窗口的尺寸(浏览器的视口,不包括工具栏和滚动条)的方法: 一.对于IE9+.Chrome.Firefox.Opera 以及 Safari: •  window.inn ...

  3. js获取浏览器窗口可视区域大小

    获得浏览器窗口的尺寸(浏览器的视口,不包括工具栏和滚动条)的方法: 一.对于IE9+.Chrome.Firefox.Opera 以及 Safari: •  window.innerHeight - 浏 ...

  4. javascript中求浏览器窗口可视区域兼容性写法

    1.浏览器窗口可视区域大小 1.1 对于IE9+.Chrome.Firefox.Opera 以及 Safari:•  window.innerHeight - 浏览器窗口的内部高度•  window. ...

  5. js/jquery获取浏览器窗口可视区域高度和宽度以及滚动条高度实现代码

    获取浏览器窗口的可视区域高度和宽度,滚动条高度有需要的朋友可参考一下.IE中,浏览器显示窗口大小只能以下获取: 代码如下复制代码 代码如下: document.body.offsetWidth doc ...

  6. 图解js中常用的判断浏览器窗体、用户屏幕可视区域大小位置的方法

    有时我们需要获得浏览器窗口或屏幕的大小.窗口下拉框下拉的距离等数据,对应这些需求,js中提供了不少解决方法,只是数量稍多容易混淆它们各自的意义,下面咱们用图例来解释下12个常见对象属性的作用. 其中有 ...

  7. JS获取浏览器可视区域尺寸

    本文所说的是浏览器窗口的可视区域大小,不是浏览器窗口大小,也非页面尺寸. 在没有声明DOCTYPE的IE中,浏览器显示窗口大小只能以下获取: document.body.offsetWidth doc ...

  8. js 获取页面可视区域宽高

    获取浏览器窗口的可视区域高度和宽度,滚动条高度有需要的朋友可参考一下. 1.IE中,浏览器显示窗口大小只能以下获取: 代码如下复制代码 代码如下 document.body.offsetWidth d ...

  9. 第51天:封装可视区域大小函数client

    一.client  可视区域     offsetWidth:   width  +  padding  +  border     (披着羊皮的狼)   clientWidth: width  + ...

随机推荐

  1. 1512 Monkey King

    Monkey King Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Tota ...

  2. (转)全网最!详!细!tarjan算法讲解

    byhttp://www.cnblogs.com/uncle-lu/p/5876729.html 全网最详细tarjan算法讲解,我不敢说别的.反正其他tarjan算法讲解,我看了半天才看懂.我写的这 ...

  3. 为Anaconda添加新的源

    为Anaconda添加新的源 在cmd中输入以下内容即可, 清华的源,速度非常快 conda config --add channels https://mirrors.tuna.tsinghua.e ...

  4. Wannafly挑战赛6

    完全平方数 时间限制:C/C++ 1秒,其他语言2秒空间限制:C/C++ 131072K,其他语言262144K64bit IO Format: %lld 题目描述 多次查询[l,r]范围内的完全平方 ...

  5. pl/sql的控制结构,分支、循环、控制

    一.pl/sql的进阶--控制结构在任何计算机语言(c,java,pascal)都有各种控制语句(条件语句,循环结构,顺序控制结构...),在pl/sql中也存在这样的控制结构.在本部分学习完成后,希 ...

  6. Unity3D - UGUI的初级应用

    添加字体: 把下载好的字体拖拽到Project面板中 - 点击Text组件中Text属性后面的圆点 - 选择刚刚拖拽的字体即可. 创建ToggleGroup(开关组): 1.在Canvas下创建两个T ...

  7. JDBC 学习笔记(四)—— JDBC 加载数据库驱动,获取数据库连接

    1. 加载数据库驱动 通常来说,JDBC 使用 Class 类的 forName() 静态方法来加载驱动,需要输入数据库驱动代表的字符串. 例如: 加载 MySQL 驱动: Class.forName ...

  8. 计算机、程序和java概述

    1.1 计算机.程序和java概述计算机包括硬件(hardware)软件(software)两部分.硬件包括计算机中看得见的物理部分,软件提供看不见的指令,指令控制硬件并且使得硬件完成特定的任务.一台 ...

  9. [转] Makefile 基础 (4) —— Makefile 书写命令

    该篇文章为转载,是对原作者系列文章的总汇加上标注. 支持原创,请移步陈浩大神博客:(最原始版本) http://blog.csdn.net/haoel/article/details/2886 我转自 ...

  10. 【Visual Studio】Visual Studio 2015快捷键设置问题 alt+ F8 (转)

    具体修改方法如下: 工具-选项-环境-键盘-应用以下其他键盘映射方案,选择visual C++6, 然后编代码试试,嘿,我的alt+F8回来了(否则是ctrl + k, ctrl + f); 原文转自 ...