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. 利用Windbg深入理解变量的存储模型

    下面的是一个简单的测试程序,基本包括了所有的变量类型,包括静态的,常量的,全局的,本地的,还有new出来的 #include <iostream> using namespace std; ...

  2. Python 前端 js基础

    Javascript 概述 JavaScript是一门编程语言,浏览器内置了JavaScript语言的解释器,所以在浏览器上按照JavaScript语言的规则编写相应代码之,浏览器可以解释并做出相应的 ...

  3. JSONP分享-- 在JavaScript中跨域请求

    如果你正在开发一个现代的基于web的应用程序,那么你: 在客户端使用JavaScript. 需要集成那些没有完全在你控制之下的服务(或者那些来自不同的域). 在你的浏览器控制台中遇到过这个错误信息: ...

  4. jQuery效果show()方法

    $("button").click(function(){ $("p").show(); }); Syntax $(selector).show(speed,e ...

  5. xml报错“cvc-complex-type.2.4.c: The matching wildcard is strict, but no declaration can be found for element”

    配置使用dubbo时,xml报错“cvc-complex-type.2.4.c: The matching wildcard is strict, but no declaration can be ...

  6. kNN的维数灾难与PCA降维

    主成分分析 PCA 协方差矩阵 假设我们有 \[ X = \begin{pmatrix}X_1\\X_2\\\vdots\\X_m\end{pmatrix}\in\mathbb{R}^{m\times ...

  7. Oracle 用户和权限

    Oracle 用户和权限Oracle 中,一般不会轻易在一个服务器上创建多个数据库,在一个数据库中,不同的项目由不同的用户访问,每一个用户拥有自身创建的数据库对象,因此用户的概念在 Oracle中非常 ...

  8. hadoop FileSystem类和SequenceFile类实例

    Hadoop的FileSystem类是与Hadoop的某一文件系统进行交互的API,虽然我们主要聚焦于HDFS实例,但还是应该集成FileSystem抽象类,并编写代码,使其在不同的文件系统中可移植, ...

  9. 【bzoj1733】[Usaco2005 feb]Secret Milking Machine 神秘的挤奶机 二分+网络流最大流

    题目描述 Farmer John is constructing a new milking machine and wishes to keep it secret as long as possi ...

  10. win install pip

    在windows下,我们使用python时,常常因为找不到需要的pthon模块,导致一些脚本不能正常执行,这时候可以安装pip工具,使用它来管理安装python所需要的模块: pip install ...