Android获取窗口可视区域大小: getWindowVisibleDisplayFrame()

getWindowVisibleDisplayFrame()方法

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

此方法的原型为

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);
  • 这里需要注意的是,由于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()方法的注释中有这样一段

Android 系统(49)---Android获取窗口可视区域大小: getWindowVisibleDisplayFrame()相关推荐

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

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

  2. 浏览器窗口可视区域大小相关方法

    一.对于IE9+.Chrome.Firefox.Opera 以及 Safari: •  window.innerHeight - 浏览器窗口的内部高度 •  window.innerWidth - 浏 ...

  3. html大小和浏览器可视区域一样吗,浏览器窗口可视区域大小

    获得浏用,事少来最差端在事路原们这制码效移,动览器窗口的尺寸(浏览器的视口,不包括工具栏和滚动条)的朋支不器几事为的时后级功发发来久都这样含制层是请些间例业多在上屏屏方法: 一.如算上处定面一这我作问 ...

  4. Android系统架构-[Android取经之路]

    摘要:本节主要来讲解Android的系统架构 阅读本文大约需要花费10分钟. 文章首发微信公众号:IngresGe 专注于Android系统级源码分析,Android的平台设计,欢迎关注我,谢谢! 欢 ...

  5. JavaScript获取浏览器可视区域的宽高

    JavaScript获取浏览器可视区域的宽高 在做项目的时候,我们常常需要对项目做一些优化,来提升页面响应的速度,比如进入可视区域后再发送请求获取数据或者是填充模板,这个时候就需要能够获取到浏览器的可 ...

  6. 【android系统】android系统升级流程分析(一)---recovery模式中进行update包升级流程分析

    今天我们直接来看下android中具体的升级过程是如何的. 升级流程概述 升级的流程图: 升级流程分析 第一步:升级包获取 升级获取可以通过远程下载,也可直接拷贝到指定目录即可. 第二步:准备升级 然 ...

  7. android log抓取方法,Android系统之Android抓取各种log的方法

    Android系统之Android抓取各种log的方法 2018年11月25日 | 萬仟网移动技术 | 我要评论 android之android抓取各种log的方法 1.logcat (四类log b ...

  8. php获取页面的可视内容高度,网页制作技巧:获取页面可视区域的高度_css

    文章简介:获取页面可视区域高度,获取页面高度,获取滚动条滚动上去的页面高度. function getWH(){ var wh = {}; "Height Width".repla ...

  9. android 服务端技术,移动应用服务器端开发(基于JSP技术)-2017 Android系统构架 Android系统构架.docx...

    Android系统构架 PAGE 1 目 录 TOC \o "1-3" \h \z \u 一.Android系统构架 1 二.Linux内核层 2 三.系统运行库层 3 (一)系统 ...

最新文章

  1. 常用的高性能 KV 存储 Redis、Memcached、etcd、Zookeeper 区别
  2. ibm笔记本电脑电池_福建省厦门市集美区电池定制供应多少钱
  3. 服务器同步什么文件类型,不同服务器同步文件类型
  4. python经典练习题
  5. 新品【国内动态】服务器列表
  6. 利用Fiddler模拟通过Dynamics 365的OAuth 2 Client Credentials认证后调用Web API
  7. 结对编程:黄金点游戏
  8. JavaScript and Ruby in ABAP
  9. 网络存储空间_Filecoin网络经济模型剖析
  10. 牛客网练习赛26B(简单的dp)
  11. 基于粒子群算法的PID控制器优化设计
  12. mac 配置host
  13. 火车采集器采集内容页分页教程
  14. Java程序员未来职业应如何规划?
  15. ios 图片居中裁剪_iOS 自定义裁剪相册照片
  16. 【服务器管理】Ubuntu的一次惊心动魄的查杀挖矿病毒的经历:病毒伪装成python
  17. 海思3559万能平台:VGS的画线处理
  18. 帮你早点下班~基于飞书API实现next.js网站内容自动生成实践
  19. 解决ubuntu下外接2k显示器却无法调2k分辨率问题
  20. MBps与Mbps区别

热门文章

  1. Shell编程基础(1)
  2. 滤波电容、去耦电容、旁路电容的作用
  3. python + opencv: 解决不能读取视频的问题
  4. 32位有符号整数_008. 字符串转换整数 (atoi) | Leetcode题解
  5. 【LeetCode】【HOT】148. 排序链表(归并排序)
  6. C++ primer第一章练习笔记及书店程序
  7. 微信小程序|开发实战篇之五-slide-view滑动菜单组件
  8. 微信小程序|开发实战篇之三
  9. 【转载】谷歌是如何做代码审查的
  10. C# ComboBox自动完成功能的例子