如何以编程方式检测 android 中可用的底部软导航栏?
How to detect bottom soft navigation bar available in android programmatically?
我试图通过android程序确定软导航栏。我没有找到直接的方法来确定。无论如何找到导航栏的可用性。
此处为软导航栏图像。
据我所知,您可以通过
检测到它
boolean hasSoftKey = ViewConfiguration.get(context).hasPermanentMenuKey();
但它需要 API 14+
如果上述解决方案对您不起作用,请尝试以下方法
public boolean isNavigationBarAvailable(){
boolean hasBackKey = KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_BACK);
boolean hasHomeKey = KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_HOME);
return (!(hasBackKey && hasHomeKey));
}
这是一个 hack,但它工作正常。试试吧。
public static boolean hasSoftKeys(WindowManager windowManager){
Display d = windowManager.getDefaultDisplay();
DisplayMetrics realDisplayMetrics = new DisplayMetrics();
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;
}
以下方法对我有效并在许多设备上进行了测试。
public boolean hasNavBar (Resources resources)
{
int id = resources.getIdentifier("config_showNavigationBar", "bool", "android");
return id > 0 && resources.getBoolean(id);
}
注意:在真机上验证了此方法
试试这个方法,通过这种方式可以检测导航栏是否存在。
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
public boolean hasNavBar(Context context) {
Point realSize = new Point();
Point screenSize = new Point();
boolean hasNavBar = false;
DisplayMetrics metrics = new DisplayMetrics();
this.getWindowManager().getDefaultDisplay().getRealMetrics(metrics);
realSize.x = metrics.widthPixels;
realSize.y = metrics.heightPixels;
getWindowManager().getDefaultDisplay().getSize(screenSize);
if (realSize.y != screenSize.y) {
int difference = realSize.y - screenSize.y;
int navBarHeight = 0;
Resources resources = context.getResources();
int resourceId = resources.getIdentifier("navigation_bar_height", "dimen", "android");
if (resourceId > 0) {
navBarHeight = resources.getDimensionPixelSize(resourceId);
}
if (navBarHeight != 0) {
if (difference == navBarHeight) {
hasNavBar = true;
}
}
}
return hasNavBar;
}
在大多数真实设备上应该可以正常工作,但在模拟器中不起作用。
但是,在 Android 4.0 及更高版本中,有一个内部 API 也适用于模拟器:IWindowManager.hasNavigationBar()。您可以使用反射访问它:
/**
* Returns {@code null} if this couldn't be determined.
*/
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
@SuppressLint("PrivateApi")
public static Boolean hasNavigationBar() {
try {
Class<?> serviceManager = Class.forName("android.os.ServiceManager");
IBinder serviceBinder = (IBinder)serviceManager.getMethod("getService", String.class).invoke(serviceManager, "window");
Class<?> stub = Class.forName("android.view.IWindowManager$Stub");
Object windowManagerService = stub.getMethod("asInterface", IBinder.class).invoke(stub, serviceBinder);
Method hasNavigationBar = windowManagerService.getClass().getMethod("hasNavigationBar");
return (boolean)hasNavigationBar.invoke(windowManagerService);
} catch (ClassNotFoundException | ClassCastException | NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
Log.w("YOUR_TAG_HERE", "Couldn't determine whether the device has a navigation bar", e);
return null;
}
}
其他答案对我没有帮助。但是了解导航栏是否显示非常有用,尤其是在 Android P/Q 之后,用户可以将其滑出屏幕。我遇到过这篇文章https://blog.stylingandroid.com/gesture-navigation-window-insets/并做了这样的方法
fun hasNavBar(activity: Activity): Boolean {
val temporaryHidden = activity.window.decorView.visibility and View.SYSTEM_UI_FLAG_HIDE_NAVIGATION != 0
if (temporaryHidden) return false
val decorView = activity.window.decorView
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
decorView.rootWindowInsets?.let{
return it.stableInsetBottom != 0
}
}
return true
}
正确答案和其他现在不是实际的。
存在一些选项,例如隐藏导航栏的 'Full Screen Display -> Full Screen Gestures',但他存在的所有这些方法 returns。
我建议您使用这种方式来检查系统视图的大小。
在 onCreate 方法中:
ViewCompat.setOnApplyWindowInsetsListener(findViewById(android.R.id.content),
(v, insets) -> {
int navigationBarHeight = insets.getSystemWindowInsetBottom();
return insets;
});
判断是否启用软导航的要点是确定提供的window大小,并根据
设置布局。
有一个非常强大的工具decorView
,可以设置之前的window,直接实现其下的方法。可以这样写:
val decorView = window.decorView
decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE
你想在框架内做什么,就开始在下面写方法吧。
在尝试了很多方法和技巧后发现这个有效,而且这是唯一有效的方法。
我试图通过android程序确定软导航栏。我没有找到直接的方法来确定。无论如何找到导航栏的可用性。
此处为软导航栏图像。
据我所知,您可以通过
检测到它boolean hasSoftKey = ViewConfiguration.get(context).hasPermanentMenuKey();
但它需要 API 14+
如果上述解决方案对您不起作用,请尝试以下方法
public boolean isNavigationBarAvailable(){
boolean hasBackKey = KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_BACK);
boolean hasHomeKey = KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_HOME);
return (!(hasBackKey && hasHomeKey));
}
这是一个 hack,但它工作正常。试试吧。
public static boolean hasSoftKeys(WindowManager windowManager){
Display d = windowManager.getDefaultDisplay();
DisplayMetrics realDisplayMetrics = new DisplayMetrics();
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;
}
以下方法对我有效并在许多设备上进行了测试。
public boolean hasNavBar (Resources resources)
{
int id = resources.getIdentifier("config_showNavigationBar", "bool", "android");
return id > 0 && resources.getBoolean(id);
}
注意:在真机上验证了此方法
试试这个方法,通过这种方式可以检测导航栏是否存在。
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
public boolean hasNavBar(Context context) {
Point realSize = new Point();
Point screenSize = new Point();
boolean hasNavBar = false;
DisplayMetrics metrics = new DisplayMetrics();
this.getWindowManager().getDefaultDisplay().getRealMetrics(metrics);
realSize.x = metrics.widthPixels;
realSize.y = metrics.heightPixels;
getWindowManager().getDefaultDisplay().getSize(screenSize);
if (realSize.y != screenSize.y) {
int difference = realSize.y - screenSize.y;
int navBarHeight = 0;
Resources resources = context.getResources();
int resourceId = resources.getIdentifier("navigation_bar_height", "dimen", "android");
if (resourceId > 0) {
navBarHeight = resources.getDimensionPixelSize(resourceId);
}
if (navBarHeight != 0) {
if (difference == navBarHeight) {
hasNavBar = true;
}
}
}
return hasNavBar;
}
但是,在 Android 4.0 及更高版本中,有一个内部 API 也适用于模拟器:IWindowManager.hasNavigationBar()。您可以使用反射访问它:
/**
* Returns {@code null} if this couldn't be determined.
*/
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
@SuppressLint("PrivateApi")
public static Boolean hasNavigationBar() {
try {
Class<?> serviceManager = Class.forName("android.os.ServiceManager");
IBinder serviceBinder = (IBinder)serviceManager.getMethod("getService", String.class).invoke(serviceManager, "window");
Class<?> stub = Class.forName("android.view.IWindowManager$Stub");
Object windowManagerService = stub.getMethod("asInterface", IBinder.class).invoke(stub, serviceBinder);
Method hasNavigationBar = windowManagerService.getClass().getMethod("hasNavigationBar");
return (boolean)hasNavigationBar.invoke(windowManagerService);
} catch (ClassNotFoundException | ClassCastException | NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
Log.w("YOUR_TAG_HERE", "Couldn't determine whether the device has a navigation bar", e);
return null;
}
}
其他答案对我没有帮助。但是了解导航栏是否显示非常有用,尤其是在 Android P/Q 之后,用户可以将其滑出屏幕。我遇到过这篇文章https://blog.stylingandroid.com/gesture-navigation-window-insets/并做了这样的方法
fun hasNavBar(activity: Activity): Boolean {
val temporaryHidden = activity.window.decorView.visibility and View.SYSTEM_UI_FLAG_HIDE_NAVIGATION != 0
if (temporaryHidden) return false
val decorView = activity.window.decorView
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
decorView.rootWindowInsets?.let{
return it.stableInsetBottom != 0
}
}
return true
}
正确答案和其他现在不是实际的。
存在一些选项,例如隐藏导航栏的 'Full Screen Display -> Full Screen Gestures',但他存在的所有这些方法 returns。
我建议您使用这种方式来检查系统视图的大小。 在 onCreate 方法中:
ViewCompat.setOnApplyWindowInsetsListener(findViewById(android.R.id.content),
(v, insets) -> {
int navigationBarHeight = insets.getSystemWindowInsetBottom();
return insets;
});
判断是否启用软导航的要点是确定提供的window大小,并根据
设置布局。有一个非常强大的工具decorView
,可以设置之前的window,直接实现其下的方法。可以这样写:
val decorView = window.decorView
decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE
你想在框架内做什么,就开始在下面写方法吧。
在尝试了很多方法和技巧后发现这个有效,而且这是唯一有效的方法。