版权声明:本文为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

NavUtils【底部虚拟导航栏工具类】的更多相关文章

  1. android: 获取屏幕高度和虚拟导航栏高度的几种方法

    package com.yongdaimi.android.androidapitest; import android.app.Activity; import android.content.Co ...

  2. Flutter实例一--底部规则导航栏制作

    先来看看制作效果: 前置知识--StatefulWidget  StatefulWidget具有可变状态(state)的窗口组件(widget).使用时要根据变化状态,调整State值, 能够快速初始 ...

  3. 5.5修改xadmin的头部底部和导航栏名称

    1.修改xadmin的头部标题和底部信息: 在users模块中的adminx.py中添加修改函数: from xadmin import views class GlobalSettings(obje ...

  4. iOS 导航栏 工具条

    导航栏最常见的例子就是返回按钮的所在 在AppDelegate.m中,代码布局最开始定义窗口的时候, _window.rootViewController就应该为一个UINavigationContr ...

  5. adjustResize模式下ExpandaleListView中输入框焦点错乱及布局底部的导航栏被顶在键盘上方的处理

    为了更好的用户体验,煎熬了许久,得到这么个解决方案.在此记录下来,以供后来者参考. 第一部分 清单文件中组件activity的android:windowSoftInputMode属性值的含义: [A ...

  6. 【Android】隐藏底部虚拟按键

    Google的官方文档是: https://developer.android.com/training/system-ui/navigation.html#behind 示例代码 1 View de ...

  7. Android应用底部导航栏(选项卡)实例

    现在很多android的应用都采用底部导航栏的功能,这样可以使得用户在使用过程中随意切换不同的页面,现在我采用TabHost组件来自定义一个底部的导航栏的功能. 我们先看下该demo实例的框架图: 其 ...

  8. 【转】Android应用底部导航栏(选项卡)实例

    现在很多android的应用都采用底部导航栏的功能,这样可以使得用户在使用过程中随意切换不同的页面,现在我采用TabHost组件来自定义一个底部的导航栏的功能. 我们先看下该demo实例的框架图: 其 ...

  9. Flutter实战视频-移动电商-03.底部导航栏制作

    03.底部导航栏制作 material是谷歌退出的 还有另外的一种:cupertino是IOS的风格 我们底部的导航栏,静态的widget是不合适的,这垃圾我们用到动态的widget 这重新改成动态的 ...

随机推荐

  1. 转载:selenium webdriver定位不到元素的五种原因及解决办法

    1.动态id定位不到元素for example:        //WebElement xiexin_element = driver.findElement(By.id("_mail_c ...

  2. SSH(Spring_SpringMVC_Hibernate)

    Users实体类 package com.tao.pojo; public class Users { private int id; private String name; private Str ...

  3. BZOJ_1654_[Usaco2007 Open]City Horizon 城市地平线_扫描线

    BZOJ_1654_[Usaco2007 Open]City Horizon 城市地平线_扫描线 Description N个矩形块,交求面积并. Input * Line 1: A single i ...

  4. BZOJ_3252_攻略_线段树+dfs序

    BZOJ_3252_攻略_线段树+dfs序 Description 题目简述:树版[k取方格数] 众所周知,桂木桂马是攻略之神,开启攻略之神模式后,他可以同时攻略k部游戏.今天他得到了一款新游戏< ...

  5. Python数据结构应用3——链表

    linked list(链表) 建立 Node 链表的基本组成就是一个个Node,每个Node都需要包括两部分内容,一部分是自身的data,另一部分是下一个Node的reference. class ...

  6. 查询APP Store已发布过的版本记录

    1.国内APP使用 酷传 搜索,即可查询到版本记录 2.国外的APP 无法通过国内软件进行搜索,可在App store中直接查询.步骤如下:

  7. BeetleX快速构建多平台的TCP和SSL TCP应用

    对于普通开发者而言编写TCP应用通讯是一件相对复杂的工作,毕竟需要一系列的bytes操作:如果再针对SSL的安全性处理相信会把很多普通开发者拒之门外.为了简化这一问题BeetleX引入了Stream操 ...

  8. Java基础知识回顾之七 ----- 总结篇

    前言 在之前Java基础知识回顾中,我们回顾了基础数据类型.修饰符和String.三大特性.集合.多线程和IO.本篇文章则对之前学过的知识进行总结.除了简单的复习之外,还会增加一些相应的理解. 基础数 ...

  9. 《k8s-1.13版本源码分析》-调度器框架

    本文原始地址(gitbook格式):https://farmer-hutao.github.io/k8s-source-code-analysis/core/scheduler/scheduler-f ...

  10. api接口参数问题

    对于取数据,我们使用最多的应该就是get请求了吧.下面通过几个示例看看我们的get请求参数传递. 回到顶部 1.基础类型参数 [HttpGet] public string GetAllChargin ...