• NavUtils【底部虚拟导航栏工具类】


    版权声明:本文为HaiyuKing原创文章,转载请注明出处!

    前言

    获取底部虚拟导航栏的高度值

    效果图

    代码分析

    checkDeviceHasNavigationBar(Context context): 检测是否存在底部虚拟导航栏

    getNavigationBarHeight(Context activity): 获取底部虚拟导航栏高度

    使用步骤

    一、项目组织结构图

    注意事项:

    1、导入类文件后需要change包名以及重新import R文件路径

    2、Values目录下的文件(strings.xml、dimens.xml、colors.xml等),如果项目中存在,则复制里面的内容,不要整个覆盖

    二、导入步骤

    将NavUtils复制到项目中

    package com.why.project.navutilsdemo.utils;
    
    import android.app.Activity;
    import android.content.Context;
    import android.content.ContextWrapper;
    import android.content.res.Resources;
    import android.os.Build;
    import android.provider.Settings;
    import android.util.DisplayMetrics;
    import android.util.Log;
    import android.view.Display;
    import android.view.WindowManager;
    
    import java.lang.reflect.Method;
    
    /**
     * Created by HaiyuKing
     * Used 底部虚拟导航栏工具类
     */
    
    public class NavUtils {
        private static final String TAG = NavUtils.class.getSimpleName();
    
        private NavUtils() {
            throw new RuntimeException("NavUtils cannot be initialized!");
        }
    
        /**
         * 获取状态栏的高度
         */
        public static int getStatusBarHeight(Context context) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
                int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
                return resourceId > 0 ? context.getResources().getDimensionPixelSize(resourceId) : 0;
            } else {
                return 0;
            }
        }
    
        /**
         * 获取底部虚拟导航栏高度
         * @param activity
         * @return
         */
        public static int getNavigationBarHeight(Context activity) {
            //方法2:有问题
            /*if (!checkDeviceHasNavigationBar(activity)) {
                return 0;
            }
            Resources resources = activity.getResources();
            int resourceId = resources.getIdentifier("navigation_bar_height",
                    "dimen", "android");
            //获取NavigationBar的高度
            int height = resources.getDimensionPixelSize(resourceId);
            return height;*/
    
            //方法1
            boolean hasNavigationBar = navigationBarExist(scanForActivity(activity)) && !vivoNavigationGestureEnabled(activity);
            Log.e(TAG,"{getNavigationBarHeight}hasNavigationBar="+hasNavigationBar);
            if (!hasNavigationBar) {//如果不含有虚拟导航栏,则返回高度值0
                return 0;
            }
            Resources resources = activity.getResources();
            int resourceId = resources.getIdentifier("navigation_bar_height",
                    "dimen", "android");
            //获取NavigationBar的高度
            int height = resources.getDimensionPixelSize(resourceId);
            return height;
        }
    
        /*========================================方法1======================================================*/
        /**
         * 通过获取不同状态的屏幕高度对比判断是否有NavigationBar
         * https://blog.csdn.net/u010042660/article/details/51491572
         * https://blog.csdn.net/android_zhengyongbo/article/details/68941464*/
        public static boolean navigationBarExist(Activity activity) {
            WindowManager windowManager = activity.getWindowManager();
            Display d = windowManager.getDefaultDisplay();
    
            DisplayMetrics realDisplayMetrics = new DisplayMetrics();
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
                d.getRealMetrics(realDisplayMetrics);
            }
    
            int realHeight = realDisplayMetrics.heightPixels;
            int realWidth = realDisplayMetrics.widthPixels;
    
            DisplayMetrics displayMetrics = new DisplayMetrics();
            d.getMetrics(displayMetrics);
    
            int displayHeight = displayMetrics.heightPixels;
            int displayWidth = displayMetrics.widthPixels;
            return (realWidth - displayWidth) > 0 || (realHeight - displayHeight) > 0;
        }
    
        /**解决java.lang.ClassCastException: android.view.ContextThemeWrapper cannot be cast to android.app.Activity问题
         * https://blog.csdn.net/yaphetzhao/article/details/49639097*/
        public static Activity scanForActivity(Context cont) {
            if (cont == null)
                return null;
            else if (cont instanceof Activity)
                return (Activity)cont;
            else if (cont instanceof ContextWrapper)
                return scanForActivity(((ContextWrapper)cont).getBaseContext());
    
            return null;
        }
    
        /**
         * 获取vivo手机设置中的"navigation_gesture_on"值,判断当前系统是使用导航键还是手势导航操作
         * @param context app Context
         * @return false 表示使用的是虚拟导航键(NavigationBar), true 表示使用的是手势, 默认是false
         * https://blog.csdn.net/weelyy/article/details/79284332#更换部分被拉伸的图片资源文件
         */
        public static boolean vivoNavigationGestureEnabled(Context context) {
            int val = Settings.Secure.getInt(context.getContentResolver(), "navigation_gesture_on", 0);
            return val != 0;
        }
    
        /*========================================方法2======================================================*/
        /**
         * 检测是否有底部虚拟导航栏【有点儿问题,当隐藏虚拟导航栏后,打开APP,仍然判断显示了虚拟导航栏】
         * @param context
         * @return
         */
        public static boolean checkDeviceHasNavigationBar(Context context) {
            boolean hasNavigationBar = false;
            Resources rs = context.getResources();
            int id = rs.getIdentifier("config_showNavigationBar", "bool", "android");
            if (id > 0) {
                hasNavigationBar = rs.getBoolean(id);
            }
            try {
                Class systemPropertiesClass = Class.forName("android.os.SystemProperties");
                Method m = systemPropertiesClass.getMethod("get", String.class);
                String navBarOverride = (String) m.invoke(systemPropertiesClass, "qemu.hw.mainkeys");
                if ("1".equals(navBarOverride)) {
                    hasNavigationBar = false;
                } else if ("0".equals(navBarOverride)) {
                    hasNavigationBar = true;
                }
            } catch (Exception e) {
            }
            return hasNavigationBar;
        }
    }

    三、使用方法

    package com.why.project.navutilsdemo;
    
    import android.os.Bundle;
    import android.support.v7.app.AppCompatActivity;
    import android.widget.TextView;
    
    import com.why.project.navutilsdemo.utils.NavUtils;
    
    public class MainActivity extends AppCompatActivity {
    
        private static final String TAG = "MainActivity";
    
        private TextView tv_show;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            tv_show = (TextView) findViewById(R.id.tv_show);
    
            int navigationBarHeight = NavUtils.getNavigationBarHeight(this);
            tv_show.setText("底部虚拟导航栏高度值为:"+navigationBarHeight + ",单位为px");
        }
    }

    混淆配置

    参考资料

    android检测导航栏是否存在的方法

    Android判断手机时候有导航栏的方法

    Android ContextThemeWrapper cannot be cast to android.app.Activity

    Android APP适配全面屏手机的技术要点

    项目demo下载地址

    https://github.com/haiyuKing/NavUtilsDemo

  • 相关阅读:
    Vue基本使用和指令集
    node.js介绍和npm的使用
    Vue基础(ES6)
    rest-framework解析器,url控制,分页,响应器,渲染器,版本控制
    JAVA的线程
    Android的存储方式
    第一个应用:一键打电话
    Android系统版本、Platform版本、SDK版本、gradle修改
    将应用代码由eclipse导入Android studio的方法NDK-Build和Cmake两种方法(以android_serialport_api为例)
    Android组件--碎片(fragment)
  • 原文地址:https://www.cnblogs.com/whycxb/p/7635745.html
Copyright © 2020-2023  润新知