Android 状态栏相关的文章网上一大堆,但是讲解导航栏的文章大多有系统兼容性问题。
本文将讲解如何准确获取导航栏高度,并且兼容性更好
先引用一下状态栏相关的网络图片
现在大部分的手机都没有底部虚拟导航键了,
但是还是有些手机厂商依然在发布带虚拟导航键的手机。
既然有,开发者就得去适配,我遇到比较麻烦的一个问题是获取屏幕(除了虚拟导航键以外的内容显示区域)高度(content)。
当时想着网上查找资料,判断是否有导航键。但是没有找到有效的方法。
最后只能转变思路,通过debug、看源码来获取高度来判断是否有导航键。
布局
通过上面的图片大致可以知道 DecorView 里有三个子View分别是statusbar、content、navigationbar。
虽然每家厂商定制ui,navigationbar高度可能不同系统不同版本都会不一致。
但是整体框架上应该不会改动,总体布局上还是这个三个布局。
所以我们可以通过获取整个手机高度,再获取content的高度便可以获取navigationbar最终高度
状态栏
获取状态栏目前有两种方法
第一种:
1 2 3 4 5 6 7 8 9 public static int getStatusBarHeight (Context context) { int result = 0 ; int resourceId = context.getResources().getIdentifier("status_bar_height" , "dimen" , "android" ); if (resourceId > 0 ) { result = context.getResources().getDimensionPixelSize(resourceId); } return result; }
第二种:
1 2 3 4 5 6 7 8 public static int getStatusBarHeight (Activity activity) { View view = activity.getWindow().getDecorView(); Rect frame = new Rect(); activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(frame); int statusBarHeight = frame.top; return statusBarHeight; }
虚拟导航栏
目前网上有许多获取虚拟导航栏的高度,但是大多数都会有些兼容性问题。
比如在OPPO、VIVO手机 上可以正确获取到高度,但在有些华为、小米部分机型上获取
到的高度有差别。下面先看下 错误 的代码
案例1:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public static int getRealHeight (Activity activity) { Window window = activity.getWindow(); View decorView = window.getDecorView(); Configuration conf = activity.getResources().getConfiguration(); if (Configuration.ORIENTATION_LANDSCAPE == conf.orientation) { View contentView = decorView.findViewById(android.R.id.content); return contentView.getWidth(); } else { Rect rect = new Rect(); decorView.getWindowVisibleDisplayFrame(rect); return rect.bottom; } }
案例1 获取的屏幕可见部分的高,有的人就会那个这个高度减去statusbar的高度,这样截屏去掉
navigationbar高度后你会发现得到的图片会有问题
案例2:
1 2 3 4 5 6 7 8 9 10 public static int getNavigationBarHeight (Context context) { int navigationBarHeight = -1 ; Resources resources = context.getResources(); int resourceId = resources.getIdentifier("navigation_bar_height" ,"dimen" , "android" ); if (resourceId > 0 ) { navigationBarHeight = resources.getDimensionPixelSize(resourceId); } return navigationBarHeight; }
案例2 这个代码是不是有点熟悉,和获取statusbar高度第一种方法差不多。
获取statusbar高度第一种方法目前是没有发现兼容性问题,而navigationbar案例2却存在这样
的问题,生产环境不可用。
其他方法就不一一列举了,网上资料一大堆,下面讲解下正确的做法。
总结
作为Android开发工程师大家都应该知道获取content的方法吧,在这个我就不贴
代码了,不知道的自己去查吧。根据上面我讲的布局逻辑,我们可以得出这样一个结论:
navigationbar的高度 = window的高度 - statusbar高度 - content的高度
也等于
navigationbar的高度 = window的高度 - content的bottom
不理解View的Top,Left,Right,Bottom属性的自行查阅资料。其中最关键的代码我在
[Android] MediaProjection 也提到过都是重点 。
正确代码:
1 2 3 4 5 6 7 8 9 10 public static int getNavigationBarRealHeight (Activity activity) { Window window = activity.getWindow(); View decorView = window.getDecorView(); Rect rect = new Rect(); decorView.getWindowVisibleDisplayFrame(rect); DisplayMetrics outMetrics = new DisplayMetrics(); WindowManager windowManager = window.getWindowManager(); windowManager.getDefaultDisplay().getRealMetrics(outMetrics); return outMetrics.heightPixels - rect.bottom; }