本篇文章主要总结一下在全面屏上获取高度的问题。

获取屏幕高度

一般 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) ,以次类推。

更多相关文章

  1. [置顶] Android ListView高度自适应和ScrollView冲突解决
  2. Android Bluetooth 学习(2)应用层实现蓝牙设备查找、tcp_ip通信
  3. 获取Android设备的方向 ,使用加速度重力传感器
  4. android 6.0后usb otg设备不显示在文件管理器中
  5. [置顶] Android设备adb授权的原理
  6. Android设备上i-jetty环境的搭建-手机上的web服务器
  7. [置顶] 我的Android进阶之旅------>Ubuntu下不能识别Android设备
  8. 【android】ListView的item高度调整
  9. Android设备开机后自动启动APP解决方法:(学习篇)

随机推荐

  1. 【Android(安卓)volley】Android库Volley
  2. Android(安卓)主流图片库Picasso Glide F
  3. Android(安卓)Q 电量使用图分析 show app
  4. 【startActivityForResult】Android(安卓
  5. [android源码下载索引贴】微信+二维码那
  6. Android中OpenMax的适配层
  7. Android中,把XML文件转换成Object对象的方
  8. android:制作system.img(yaffs2)镜像
  9. Android上的模拟点击
  10. android实践项目一实现简单的验证码和spi