有人会问,这些key都是哪里来的?毕竟我在厂商文档也没有翻到 。
我能想到的办法是查看SettingsProvider,它是提供设置数据的Provider,分有Global、System、Secure三种类型,上面代码中可以看到不同品牌存放在的类型都不同 。我们可以通过adb命令查看所有数据,根据navigation等关键字去寻找 。比如查看Secure的数据:
adb shell settings list secure
或者:
ContentResolver cr = context.getContentResolver();Uri uri = Uri.parse("content://settings/secure/");Cursor cursor = cr.query(uri, null, null, null, null);while (cursor.moveToNext()) {String name = cursor.getString(cursor.getColumnIndex("name"));String value = https://www.isolves.com/it/cxkf/bk/2020-12-31/cursor.getString(cursor.getColumnIndex("value"));Log.d("settings:", name + "=" + value);}cursor.close();
这样如果有上面兼容不到的机型,可以使用这个方法适配 。也欢迎你的补充反馈 。
费了这么大的劲获取到了准确的高度,可能你会说,还不如直接获取ContentView的高度:
public static int getContentViewHeight(Activity activity) {View contentView = activity.getWindow().getDecorView().findViewById(android.R.id.content);return contentView.getHeight();}
这个结果和上述计算的高度一致,唯一的限制是需要在onWindowFocusChanged之后调用,否则高度为0 。这个我们可以根据实际情况自行选用 。
已知问题
- 网上有许多同类代码,发现会将vivo和oppo都使用navigation_gesture_on这一个key 。我在oppo Find x中发现此key并不存在,不知是否和系统版本有关 。如果是的话,又需要判断oppo的系统版本了 。
- 上面提到的获取导航栏高度的方法在部分手机中无效,无效的原因是因为导航栏隐藏时,获取高度就为0 。所以判断是否显示导航栏是关键 。
- 刘海的出现,很多人会吐槽丑,所以厂家想到了隐藏刘海的方式(掩耳盗铃),比如下面是Redmi K30的设置页面:
文章插图
设置刘海显示页
第二种没啥特别,就是状态栏强制为黑色 。这里我怀疑因为这个设置,导致在有刘海的手机上,ScreenHeight不包含状态栏高度 。
最糟糕的是第三种,隐藏后状态栏在刘海外 。例如Redmi K30在开启后,ScreenHeight 为2174,RealHeight为2304,而关闭时为2175 和 2400 。这下连万年不变的RealHeight也变化了,这太不real了,大家自行体会 。不过目前发现未影响适配方案,不知其他手机如何 。
对于是否隐藏刘海,其实也是有各家的判断的,比如小米:
// 0:显示刘海,1:隐藏刘海Settings.Global.getInt(context.getContentResolver(), "force_black", 0);
- 有些App会使用修改density的屏幕适配方案,这会影响获取导航栏高度的方法 。比如130px的导航栏适配后获取到的是136px 。所以这里需要使用getSystem中的density转换回去:
public static int getNavigationBarHeight(Context context){int resourceId = context.getResources().getIdentifier("navigation_bar_height", "dimen", "android");if (resourceId > 0) {int height = context.getResources().getDimensionPixelSize(resourceId);// 兼容屏幕适配导致density修改float density = context.getResources().getDisplayMetrics().density;if (DENSITY != density) {return dpToPx(px2dp(context, height));}return height;}return 0;}public static final float DENSITY = Resources.getSystem().getDisplayMetrics().density;public static int dpToPx(int dpValue) {return (int) (dpValue * DENSITY + 0.5f);}public static int px2dp(Context context, int px) {return (int) (px / context.getResources().getDisplayMetrics().density + 0.5);}
getSystem源码如下:/*** Return a global shared Resources object that provides access to only* system resources (no application resources), is not configured for the* current screen (can not use dimension units, does not change based on* orientation, etc), and is not affected by Runtime Resource Overlay.*/public static Resources getSystem() {synchronized (sSync) {Resources ret = mSystem;if (ret == null) {ret = new Resources();mSystem = ret;}return ret;}}
它不受资源覆盖的影响,我们可以通过它将值转换回来 。展望未来本篇看似聊的获取高度这件事,其实伴随导航栏的发展演进,核心是是如何判断导航栏是否显示 。
通过上面的介绍,总结一下就是在“全面屏时代”,如果你想获取屏幕高度,就不要使用ScreenHeight了 。否则会出现UI展示上的问题 。而且这种问题,线上也不会崩溃,难以发现 。以前在支付宝中就发现过 PopupWindow弹出高度不正确的问题,过了好久才修复了 。
推荐阅读
- 鲁大师跑分多少算好电脑?
- 娄师德是哪里人 对娄师德的评价
- 浅谈常用的架构模式
- 秦国第一个丞相王绾 汉武帝老师卫绾
- 伍子胥申包胥对话 申包胥如秦乞师
- 网络工程师如何用思科路由器配置GRE Over IPsec
- 林治老师即将开班,六安茶业技术培训班正式开班
- 安溪茶校老师,安溪茶校获佳绩
- 美容师经期能碰精油吗
- 浅谈聊天系统架构设计