需求
今天的需求是要获取到状态栏的高度没因为UI是全屏填充到顶部。通过margin来控制是否显示到状态栏下面。
在网上看到一个见解:
不同的Android设备状态栏的高度不一样。240x320高度是20px,320x480高度是25px,480x800是38px。记得以前有人说是25px,所以是不对的。获取方式是根据Window来获取:
1 | Rect rectangle = new Rect(); |
height-of-status-bar-in-android
将这块整理一下。getWindowVisibleDisplayFrame()
从方法的描述老看:获取窗口可视区域,方法需要IPC的支持,所以不应该用在关键处的代码(critical code),比如draw方法中。而且需要View已经attach到Window的时候才会有值。
由于getWindowVisibleDisplayFrame()方法是View类下的一个方法,所以只能通过View对象来调用。一个窗口中通常都会有多个View,getWindowVisibleDisplayFrame()方法的返回结果和该窗口中选取的View并没有关系。在某个时刻,使用当前窗口中的任意View执行getWindowVisibleDisplayFrame()返回的结果都是一样的
getWindowVisibleDisplayFrame()方法返回的是窗口的可视区域大小,并非某个View的可视区域大小,所以用窗口中的任意View来执行都是没有差别的。
联系之屏幕的划分
手机展示的界面从上到下依次是
- 状态栏(包含通知,系统时间),
- 然后是应用的标题栏,
- 应用的View布局栏,
- 以及底部的导航栏。
有的手机有实体按钮所有没有底部的导航栏。
获取屏幕的宽、高
1 | DisplayMetrics metrics = new DisplayMetrics(); |
状态栏
1 | Rect rect= new Rect(); |
View布局绘制区域即Content
1 | Rect rect = new Rect(); |
标题栏
1 | int contentViewTop = |
应用内容区域=>标题栏+View布局绘制区域
1 | Rect rect = new Rect(); |
导航栏
1 | Resources resources = getResources(); |
结果
一个Activity是附着在一个Window上的。Window中包含一个顶级视图DecorView,
DecorView中只有一个线性布局的child叫mContentRoot。mContentRoot包含mContentparent、标题栏。而mContentParent就是setContentView所加载的布局的容器,资源id是content。
getDecorView()
是不包含状态栏的。所以他的区域rect.top
就是状态栏高度。getWindow().findViewById(Window.ID_ANDROID_CONTENT).getDrawingRect(rect)
就是获取的内容区域,所以rect.top
获取的就是状态栏的标题栏的高度。
所以屏幕的高度=状态栏高度+DecorView高度+导航栏的高度
=状态栏高度+标题栏高度+content高度+导航栏高度
但是结果并不是这样:
(Px_XL_1440x2560)
标题栏和content的高度与decorView的高度之间差了一个状态栏的高度。奇怪?
状态栏和导航栏肯定是对的,因为直接从资源里面取出来的,decorView的高度是直接获取的没有问题。问题就出在标题栏高度、content高度上。
手动将标题栏和content高度打印出来:
以及content的top,windowFrame以及DrawingRect打印出来:
日志:
发现window的高度是2392,content的bottom-top
等于2112,获取到的高度也是2112。所以content的高度是对的。哪问题就出在title的高度了,两个的差值是196。
刚刚求标题栏高度是contentViewTop-statusBarHeight
。所以问题就出在这,因为:
contentViewTop
就是content在父容器DecorView的坐标位置,就是标题栏的高度。
所以标题栏高度:
1 | int contentViewTop = |
noActionBar:
参考
Android获取窗口可视区域大小: getWindowVisibleDisplayFrame()
android 屏幕划分
深入浅析Android坐标系统