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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM