zoukankan      html  css  js  c++  java
  • 判断虚拟导航栏(NavigationBar)是否显示

    随着国产全面屏的普及,适配的坑是愈发的多……

    今天咱们别的不聊,就来唠唠如何判断虚拟导航栏(NavigationBar)是否显示

    在五花八门的国产手机面前,虚拟导航栏的判断真是一件令人头疼的事。没有什么直接的方式,可以判断虚拟导航栏的显示情况。

    参考方案找了一堆,都多少存在着一些问题。既然这样我们就从原始需求出发,把判断步骤一步步分解:

    • 首先判断虚拟导航栏的高度是否为0,如果为0,此时虚拟导航栏不显示;
    • 判断是否开启手势操作,如果开启手势操作,此时虚拟导航栏也是不显示的;
    • 剩下的情况,根据屏幕真实高度与显示高度,判断虚拟导航栏是否显示。

    经过多方搜寻,我们找来了:华为手机、小米手机、VIVO手机,手势操作的相关配置。我们可以通过反射,拿到具体的属性设置。

    那我们就直奔主题,将完整的判断代码贴出来:

    object NavigationUtils {
    
        /**
         * 获取虚拟导航栏(NavigationBar)的高度,可能未显示
         */
        fun getNavigationBarHeight(context: Context): Int {
            var result = 0
            val resources = context.resources
            val resourceId = resources.getIdentifier("navigation_bar_height", "dimen", "android")
            if (resourceId > 0) result = resources.getDimensionPixelSize(resourceId)
            return result
        }
    
        /**
         * 获取虚拟导航栏(NavigationBar)是否显示
         * @return true 表示虚拟导航栏显示,false 表示虚拟导航栏未显示
         */
        fun hasNavigationBar(context: Context) = when {
            getNavigationBarHeight(context) == 0 -> false
            RomUtils.checkIsHuaweiRom() && isHuaWeiHideNav(context) -> false
            RomUtils.checkIsMiuiRom() && isMiuiFullScreen(context) -> false
            RomUtils.checkIsVivoRom() && isVivoFullScreen(context) -> false
            else -> isHasNavigationBar(context)
        }
    
        /**
         * 华为手机是否隐藏了虚拟导航栏
         * @return true 表示隐藏了,false 表示未隐藏
         */
        private fun isHuaWeiHideNav(context: Context) =
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
                Settings.System.getInt(context.contentResolver, "navigationbar_is_min", 0)
            } else {
                Settings.Global.getInt(context.contentResolver, "navigationbar_is_min", 0)
            } != 0
    
        /**
         * 小米手机是否开启手势操作
         * @return true 表示使用的是手势,false 表示使用的是虚拟导航栏(NavigationBar),默认是false
         */
        private fun isMiuiFullScreen(context: Context) =
            Settings.Global.getInt(context.contentResolver, "force_fsg_nav_bar", 0) != 0
    
        /**
         * Vivo手机是否开启手势操作
         * @return true 表示使用的是手势,false 表示使用的是虚拟导航栏(NavigationBar),默认是false
         */
        private fun isVivoFullScreen(context: Context) =
            Settings.Secure.getInt(context.contentResolver, "navigation_gesture_on", 0) != 0
    
        /**
         * 根据屏幕真实高度与显示高度,判断虚拟导航栏是否显示
         * @return true 表示虚拟导航栏显示,false 表示虚拟导航栏未显示
         */
        private fun isHasNavigationBar(context: Context): Boolean {
            val windowManager: WindowManager =
                context.getSystemService(Service.WINDOW_SERVICE) as WindowManager
            val display = windowManager.defaultDisplay
    
            val realDisplayMetrics = DisplayMetrics()
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
                display.getRealMetrics(realDisplayMetrics)
            }
            val realHeight = realDisplayMetrics.heightPixels
            val realWidth = realDisplayMetrics.widthPixels
    
            val displayMetrics = DisplayMetrics()
            display.getMetrics(displayMetrics)
            val displayHeight = displayMetrics.heightPixels
            val displayWidth = displayMetrics.widthPixels
    
            // 部分无良厂商的手势操作,显示高度 + 导航栏高度,竟然大于物理高度,对于这种情况,直接默认未启用导航栏
            if (displayHeight > displayWidth) {
                if (displayHeight + DisplayUtils.getNavigationBarHeight(context) > realHeight) return false
            } else {
                if (displayWidth + DisplayUtils.getNavigationBarHeight(context) > realWidth) return false
            }
    
            return realWidth - displayWidth > 0 || realHeight - displayHeight > 0
        }
    }
    

    上述代码有一点需要提一下:

    根据屏幕真实高度与显示高度,判断虚拟导航栏的显示情况。原以为通过两值是否相等就能判断,但是在部分OPPO手机上,还是发现了问题:显示高度小于屏幕高度,但虚拟导航栏并未显示

    在原生安卓的手势操作上,并不是完全的全屏显示;而是将导航栏变成小小的一条,并配合上手势操作;此时的导航栏高度,也是变小之后的值。

    但是在部分OPPO手机上,导航栏的高度并未变化,但屏幕高度和显示高度却有一个小差值。

    针对这种情况,我们要做的就是:判断显示高度 + 导航栏高度,是否大于屏幕高度。如果大于屏幕高度,则认为此时导航栏并未显示。还有一些屏幕旋转的问题,我们处理的时候也需要注意一下。

    上述代码各方搜集并加以完善,目前测试过一些华为手机、小米手机、OPPO手机是可以正常判断的。如果大家在使用中有什么问题,可以一起反馈、完善。

    代码中用到的ROM判断工具:RomUtils.kt



    作者:呱呱_
    链接:https://www.jianshu.com/p/f13963c8e46c
    来源:简书
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  • 相关阅读:
    topcoder srm 320 div1
    topcoder srm 325 div1
    topcoder srm 330 div1
    topcoder srm 335 div1
    topcoder srm 340 div1
    topcoder srm 300 div1
    topcoder srm 305 div1
    topcoder srm 310 div1
    topcoder srm 315 div1
    如何统计iOS产品不同渠道的下载量?
  • 原文地址:https://www.cnblogs.com/zhujiulunjian/p/14075623.html
Copyright © 2011-2022 走看看