版權聲明:本文為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 ContextThemeWrapper cannot be cast to android.app.Activity
