Android 获取屏幕高度,虚拟导航键检测
本篇文章主要总结一下在全面屏上获取高度的问题。
获取屏幕高度
一般 Android 上获取设备的高度都是通过 DefaultDisplay 的方式来获取的如下:
public int getScreenHeight(Activity activity){ WindowManager manage = activity.getWindowManager(); Display display = manage.getDefaultDisplay(); return display.getHeight();}
不过后来 Display.getHeight 被标记过时了,所以就用下面这个方式来代替:
public int getScreenHeight(Activity activity){ WindowManager manage = activity.getWindowManager(); DisplayMetrics dm = new DisplayMetrics(); return manage.getDefaultDisplay().getMetrics(dm).heightPixels;}
上面两种方法在之前的设备上都是没有问题的,但是随着 Android 设备的发展,虚拟导航键、全面屏手势的普及加之不同的厂商对这个方法的处理不相同,导致很多时候通过 getScreenHeight 获取到的方法出现一些偏差,最明显的就是在一些设备上如果用户隐藏了导航键使用全面屏手势,这个方法返回的要比实际的小。具体可以看下表
设备 | 导航键类型 | 系统版本 | 高度 | getScreenHeight |
---|---|---|---|---|
1加3T | 物理 | 8.0.0 | 1920 | 1920 |
Nexus 6 | 虚拟 | 7.1.1 | 2560 | 2392 |
诺基亚x6 | 隐藏 | 8.1.0 | 2280 | 2154 |
诺基亚x6 | 虚拟 | 8.1.0 | 2280 | 2154 |
荣耀7X | 虚拟 | 8.0.0 | 2160 | 2038 |
荣耀7X | 隐藏 | 8.0.0 | 2160 | 2160 |
诺基亚x71 | 隐藏 | 9.0 | 2310 | 2081 |
诺基亚x71 | 虚拟 | 9.0 | 2310 | 2081 |
小米mix3 | 隐藏 | 9.0 | 2340 | 2210 |
oppoR15 | 隐藏 | 9.0 | 2280 | 2280 |
oppoR15 | 虚拟 | 9.0 | 2280 | 2056 |
可以大概看出来在9.0以下的手机上 getScreenHeight 如果有虚拟导航键获取到的是真实的设备屏幕高度,即除去虚拟导航键的高度,如果没有虚拟导航键则各个手机不一样;在9.0的手机上也是表现各不相同,所以需要有一个根据不同的情况来判断。
获取真实的高度
获取真实的设备高度可以使用 Deisplay.getRealSize 来获取,但是这个获取到的是设备高度,所以在有虚拟导航键的情况可以使用 getScreenHeight 来获取高度,在隐藏虚拟导航键的情况下可以使用 Deisplay.getRealSize 来获取:
/** * 判断设备的真实高度,即app界面真实使用的高度 * * @return */ public static int getRealScreenHeight(Context context) { if (!isNavBarHide(context)) { // 如果没有隐藏导航键则正常返回 return DeviceInfo.getScreenHeight(); } try { Point point = new Point(); ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getRealSize(point); return point.y; } catch (Exception e) { e.printStackTrace(); return DeviceInfo.getScreenHeight(); } }
下面看一下怎么判断是否隐藏了虚拟导航键。
判断导航键是否隐藏
判断是否隐藏了导航键,可以通过监听一个 ContentResolver 来实现,其实下面的方法经过验证正确可用:
/** * 是否隐藏了导航键 * * @param context * @return */ public static boolean isNavBarHide(Context context) { try { String brand = Build.BRAND; // 这里做判断主要是不同的厂商注册的表不一样 if (!Utils.isStringEmpty(brand) && (brand.equalsIgnoreCase("VIVO") || brand.equalsIgnoreCase("OPPO"))) { return Settings.Secure.getInt(context.getContentResolver(), getDeviceForceName(), 0) != 0; } else if (!Utils.isStringEmpty(brand) && brand.equalsIgnoreCase("Nokia")) { //甚至 nokia 不同版本注册的表不一样, key 还不一样。。。 return Settings.Secure.getInt(context.getContentResolver(), "swipe_up_to_switch_apps_enabled", 0) == 1 || Settings.System.getInt(context.getContentResolver(), "navigation_bar_can_hiden", 0) != 0; } else return Settings.Global.getInt(context.getContentResolver(), getDeviceForceName(), 0) != 0; } catch (Exception e) { e.printStackTrace(); } return false; } /** * 各个手机厂商注册导航键相关的 key * * @return */ public static String getDeviceForceName() { String brand = Build.BRAND; if (Utils.isStringEmpty(brand)) return "navigationbar_is_min"; if (brand.equalsIgnoreCase("HUAWEI") || "HONOR".equals(brand)) { return "navigationbar_is_min"; } else if (brand.equalsIgnoreCase("XIAOMI")) { return "force_fsg_nav_bar"; } else if (brand.equalsIgnoreCase("VIVO")) { return "navigation_gesture_on"; } else if (brand.equalsIgnoreCase("OPPO")) { return "hide_navigationbar_enable"; } else if (brand.equalsIgnoreCase("samsung")) { return "navigationbar_hide_bar_enabled"; } else if (brand.equalsIgnoreCase("Nokia")) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) { return "navigation_bar_can_hiden"; } else { return "swipe_up_to_switch_apps_enabled"; } } else { return "navigationbar_is_min"; } }
也有很多资料里面给出了相似的方法,但是有些给出的key以及表是不对的,比如 oppo 、诺基亚的,关于这些key 除了参考厂商给出的资料外,也可以通过观察系统日志的方法来获取,比如 oppo 在切换导航方式的时候会有下面的 log:
2019-10-24 17:39:23.660 1376-1376/? V/SettingsProvider: Notifying for 0: content://settings/secure/hide_navigationbar_enable2019-10-24 17:39:23.661 20487-20487/? I/StatusBar: mHideNavigationBarObserver mode:22019-10-24 17:39:23.661 1376-1402/? V/SettingsProvider: getSecureSetting(wake_gesture_enabled, getCallingPackage = android2019-10-24 17:39:23.662 5100-5100/? I/ColorNavigationBarUtil: setImePackageInGestureMode isImeInGestureMode:true2019-10-24 17:39:23.662 1376-1402/? D/WindowManager: updateSettings: incallPowerButtonHangup = 02019-10-24 17:39:23.663 1376-1402/? D/WindowManager: updateSettings: powerButtonEndsAlarmclock = 02019-10-24 17:39:23.664 20577-20577/? I/ColorRecentsStateController: onChange() mNavbarEnable = 2
content://settings/secure/hide_navigationbar_enable
就是我们要监听的内容,对应的就是 Settings.Secure.getInt(context.getContentResolver(), "hide_navigationbar_enable", 0)
,以次类推。
更多相关文章
- [置顶] Android ListView高度自适应和ScrollView冲突解决
- Android Bluetooth 学习(2)应用层实现蓝牙设备查找、tcp_ip通信
- 获取Android设备的方向 ,使用加速度重力传感器
- android 6.0后usb otg设备不显示在文件管理器中
- [置顶] Android设备adb授权的原理
- Android设备上i-jetty环境的搭建-手机上的web服务器
- [置顶] 我的Android进阶之旅------>Ubuntu下不能识别Android设备
- 【android】ListView的item高度调整
- Android设备开机后自动启动APP解决方法:(学习篇)