以编程方式检测android设备中的软导航栏可用性?
我试图通过android程序确定软导航栏。我没有找到直接的方法来确定。是否仍然可以找到可用的导航栏 软导航栏图像在这里以编程方式检测android设备中的软导航栏可用性?,android,android-layout,android-ui,android-navigation,Android,Android Layout,Android Ui,Android Navigation,我试图通过android程序确定软导航栏。我没有找到直接的方法来确定。是否仍然可以找到可用的导航栏 软导航栏图像在这里 据我所知,您可以通过 boolean hasSoftKey = ViewConfiguration.get(context).hasPermanentMenuKey(); 但它需要API 14+ 如果上述解决方案不适用于您,请尝试以下方法 public boolean isNavigationBarAvailable(){ boolean hasBackK
据我所知,您可以通过
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));
}
这是一个黑客,但它工作得很好。试试看
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也可以在模拟器上工作:。您可以使用反射来访问它:
/**
* 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;
}
}
/**
*如果无法确定,则返回{@code null}。
*/
@TargetApi(构建版本代码冰淇淋三明治)
@SuppressLint(“PrivateApi”)
公共静态布尔hasNavigationBar(){
试一试{
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”);
对象windowManagerService=stub.getMethod(“asInterface”,IBinder.class).invoke(stub,serviceBinder);
方法hasNavigationBar=windowManagerService.getClass().getMethod(“hasNavigationBar”);
return(布尔值)hasNavigationBar.invoke(windowManagerService);
}捕获(ClassNotFoundException | ClassCastException | NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e){
Log.w(“您的标签在这里”,“无法确定设备是否有导航栏”,e);
返回null;
}
}
其他答案对我没有帮助。但知道导航栏是否显示是非常有用的,特别是在Android P/Q之后,用户可以将其从屏幕上滑出。我遇到过这篇文章,并提出了这样的方法
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
}
正确答案和其他答案现在都不实际
存在一些选项,如“全屏显示->全屏手势”,其中导航栏是隐藏的,但所有这些方法都返回他在场 我建议您使用这种方法来检查系统视图的大小。 在onCreate方法中:
谢谢你的回复。我正在查找是否存在软导航栏。设备没有永久菜单键与设备有软导航栏不相等。有些设备没有永久菜单键,也没有软导航栏。请查看此设备感谢您提供的大量信息,因为这类设备,您可以尝试我的第二种解决方案(查看更新的答案)谢谢。看来对我有用。我按预期在两台可用设备上进行了测试。享受编程,如果这个答案对你有帮助,那么接受答案或投票将非常感激:-)这段代码可以工作,但不是“android”使用,“android”在这两种情况下都返回
false
。请注意,在android模拟器上总是返回false
。请参阅以获取解释。尽管不在模拟器上工作,但这非常接近,因此在实际设备上应该非常准确。选中1+3启用这两个选项总是返回false。当然,使用内部api类型的stings,但嘿,它可以在我的所有设备上工作(至少在API25之前)。Extra+用于不依赖上下文。它对我有效,但我收到了一条警告,提示我可能会出现空指针异常。它使用安全吗?@Dahnark它是一个内部API,所以不能保证它能在给定的设备上工作。我的示例中的方法返回null
,因此您可以检测它何时不起作用。您需要决定发生这种情况时要做什么,并为其添加代码。@Sam我知道,但有可能避免此警告吗?实际上,我正在使用if-else来表示这三种可能性(有导航、没有导航、空),但我仍然得到了警告。@Dahnark哦,我明白了。我不知道对不起。我同意这是一个黑客行为,但很好。Kudos这可能不适用于新的华为P20和其他带有顶部缺口的设备。请编辑您的答案,解释您提供的代码。在你的答案中直接对代码进行解释将有助于未来的读者理解代码的作用和方式。我的答案中有什么不清楚的地方?第一部分是检查活动窗口decorView的隐藏导航ui可见性标志,第二部分是检查这些decorView的底部插图。从23 API开始工作。没有什么特别不清楚的,但通常鼓励在这个网站上评论或解释代码片段。OP提出这个问题是因为他们不知道如何解决这个问题,这可能意味着他们从未在代码中看到过某些或任何单独的语句(如果他们以前看到过,他们可能自己就解决了这个问题)。因此,检查并为代码的每个部分添加注释是有价值的。解释可以进入答案本身,而不是评论,请。伟大的工作!但您应该稍微调整一下代码,因为这只适用于纵向模式,但设备也可能是横向的。
ViewCompat.setOnApplyWindowInsetsListener(findViewById(android.R.id.content),
(v, insets) -> {
int navigationBarHeight = insets.getSystemWindowInsetBottom();
return insets;
});