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. 前端 五——ajax

    内容概要: 1.ajax的特点 2.基于JS的ajax 3.基于jQuery的ajax 1.特点: 局部刷新 异步传送(交互) 缺点: (1)无形中向服务器发送的请求次数太多,导致服务器压力增大. ( ...

  2. 实现类似QQ单一账户登录,在另一个地方登录后在原登录窗口提示下线

    首先,使用框架做的最好,可以在框架页直接做一次就好了 再登陆成功后保存session的代码后添加以下代码: 注意:需要引入命名空间using System.Collections; SetApplic ...

  3. webdriver高级应用- 精确比较页面截图图片

    判断两张图是否完全一致,如果存在任何不一致,会认为图片不匹配,代码如下: #encoding=utf-8 from selenium import webdriver import unittest, ...

  4. 自己的Qt GUI 项目+vs2013+opencv+caffe环境配置

    由于深度学习的种种优势,使我们对于深度学习的使用越来越频繁.很多时候,我们都需要在自己的项目中配置caffe环境,来调用caffe网络模型完成自己的任务.今天我主要讲的关于"在自己的项目中配 ...

  5. JDBC 学习笔记(一)—— JDBC 基础

    1. 什么是 JDBC JDBC,Java Database Connectivity(Java 数据库连接),是一组执行 SQL 语句的 Java API. JDBC,是 Java SE(Java ...

  6. 【Luogu】P3979遥远的国度(树链剖分)

    题目链接 不会换根从暑假开始就困扰我了……拖到现在…… 会了还是很激动的. 换根操作事实上不需要(也不能)改树剖本来的dfs序……只是在query上动动手脚…… 设全树的集合为G,以root为根,u在 ...

  7. [LOJ#522]「LibreOJ β Round #3」绯色 IOI(危机)

    [LOJ#522]「LibreOJ β Round #3」绯色 IOI(危机) 试题描述 IOI 的比赛开始了.Jsp 和 Rlc 坐在一个角落,这时他们听到了一个异样的声音 …… 接着他们发现自己收 ...

  8. [luoguP2763] 试题库问题(最大流)

    传送门 每个类别和它所有的试题连一条权值为1的边. 增加一个超级源点s,s和每个类别连一条权值为选当前类别数量的边. 增加一个超级汇点t,每个试题和t连一条权值为1的边. 求最大流即可. ——代码 # ...

  9. 论蛋疼的调戏matrix67的首页

    唔,初学js,然后拿matrix67的首页玩玩23333 console 里输入以下这句话 for(var i = 1; i <= 400; i++){var td = document.get ...

  10. babel吐槽

    1. .babelrc文件无法复制 每次复制项目文件,.babelrc文件都会丢失,导致项目的ES6莫名的编译失败,最可能出现的错误就是Unexpected token import错误,import ...