如何在Android中真正获取导航栏高度

13

我拥有一台能够隐藏导航栏的HTC One A9手机。在我的应用程序中,我需要获取导航栏的高度并设置相应的填充。现在出现了一个问题:当我隐藏导航栏时,仍然设置填充(即使Snapchat也有这个问题)。我的问题是:是否有其他代码可以替代这个代码使其工作?

public static int getNavBarHeight(Context context) {
    int result = 0;
    int resourceId = context.getResources().getIdentifier("navigation_bar_height", "dimen", "android");
    if (resourceId > 0) {
        result = context.getResources().getDimensionPixelSize(resourceId);
    }
    return result;
}

谢谢你的帮助!


你想要实现什么?请详细说明一下。也许你根本不需要计算导航栏的高度。 - shaktiman_droid
@Jabbar_Jigariyo 我需要为底部视图设置填充,该视图包含图像按钮等,当用户有一个导航栏时(我正在使用透明导航栏)。 - Made by FA
如果您正在使用透明的导航栏,那么为什么还需要隐藏它呢?对于那些具有导航栏的设备,它已经是透明的了,而对于那些具有物理按钮的设备,就没有导航栏了。是吗? - shaktiman_droid
我假设你在你的主题中使用了 android:windowTranslucentNavigation - shaktiman_droid
@Jabbar_Jigariyo HTC One A9配备了一个指纹传感器,可作为主页按钮使用。是的,我是。 - Made by FA
显示剩余2条评论
5个回答

11

这是我用来获取导航栏大小的代码。其高度将在Point.y中。

鸣谢此答案

public static Point getNavigationBarSize(Context context) {
    Point appUsableSize = getAppUsableScreenSize(context);
    Point realScreenSize = getRealScreenSize(context);

    // navigation bar on the right
    if (appUsableSize.x < realScreenSize.x) {
        return new Point(realScreenSize.x - appUsableSize.x, appUsableSize.y);
    }

    // navigation bar at the bottom
    if (appUsableSize.y < realScreenSize.y) {
        return new Point(appUsableSize.x, realScreenSize.y - appUsableSize.y);
    }

    // navigation bar is not present
    return new Point();
}

public static Point getAppUsableScreenSize(Context context) {
    WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
    Display display = windowManager.getDefaultDisplay();
    Point size = new Point();
    display.getSize(size);
    return size;
}

public static Point getRealScreenSize(Context context) {
    WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
    Display display = windowManager.getDefaultDisplay();
    Point size = new Point();

    if (Build.VERSION.SDK_INT >= 17) {
        display.getRealSize(size);
    } else if (Build.VERSION.SDK_INT >= 14) {
        try {
            size.x = (Integer)     Display.class.getMethod("getRawWidth").invoke(display);
            size.y = (Integer) Display.class.getMethod("getRawHeight").invoke(display);
    } catch (IllegalAccessException e) {} catch     (InvocationTargetException e) {} catch (NoSuchMethodException e) {}
    }

    return size;
}

编辑:为了回答您的问题,我不得不使用这个函数,因为我想将ResideMenu添加到我的应用程序中,但最终出现了一个奇怪的空白边距在我的应用程序底部,因为导航栏的原因。

所以我像这样修改了ResideMenu添加的这个函数:

@Override
protected boolean fitSystemWindows(Rect insets) {
    // Applies the content insets to the view's padding, consuming that content (modifying the insets to be 0),
    // and returning true. This behavior is off by default and can be enabled through setFitsSystemWindows(boolean)
    // in API14+ devices.

    int bottomPadding = insets.bottom;

    Point p = getNavigationBarSize(getContext());

    if (Build.VERSION.SDK_INT >= 21 && p.x != 0) {
        Resources resources = getContext().getResources();
        int resourceId = resources.getIdentifier("navigation_bar_height", "dimen", "android");
        if (resourceId > 0) {
            bottomPadding += resources.getDimensionPixelSize(resourceId);
        }
    }

    this.setPadding(viewActivity.getPaddingLeft() + insets.left, viewActivity.getPaddingTop() + insets.top,
            viewActivity.getPaddingRight() + insets.right, viewActivity.getPaddingBottom() + bottomPadding);
    insets.left = insets.top = insets.right = insets.bottom = 0;
    return true;
}

希望这能对你有所帮助。


谢谢!那么我该如何在布局中使用这个点来设置填充等呢?谢谢! - Made by FA
我编辑了我的答案,展示了如何在我的代码中使用这个点。 - ToinToin
你在第一个代码片段中缺少两个关键方法的代码。 - milosmns
3
@ToinToin,请注明你复制整个代码的来源 the answer - Sufian
太棒了!ResideMenu解决方案非常好。帮了我很多忙!谢谢。 - User

2

使用以下代码获取导航栏。但是,您需要考虑多窗口模式以及导航栏是否位于窗口的底部、左侧或右侧。

getNavigationBarHeight(){
    Resources resources = context.getResources();
    int resourceId = resources.getIdentifier("navigation_bar_height", "dimen", "android");
    if (resourceId > 0) {
        return resources.getDimensionPixelSize(resourceId);
    }
    return 0;
}

1

以下是最简单的答案。 你只需要传递活动的rootView。如果不显示栏,则高度为0

View rootView;
ViewCompat.setOnApplyWindowInsetsListener(rootView, (v, insets) -> {
    final int statusBarHeight = insets.getInsets(WindowInsetsCompat.Type.statusBars()).top; // in px
    final int navigationBarHeight = insets.getInsets(WindowInsetsCompat.Type.navigationBars()).bottom; // in px

    // do something with the heights

    return WindowInsetsCompat.CONSUMED;
});

这是什么鬼?所有操作完成后,哪个变量等于高度? - Math Machine
@MathMachine 代码非常清晰。如果您有问题,请指出具体的位置。 - Faisal Khan
@MathMachine 当OnApplyWindowInsetsListener回调被调用时,导航栏高度将会被存储在lambda函数中的int navigationBarHeight变量中。由于高度是通过异步回调获得的,因此您需要相应地使用获得的高度。 - Faisal Khan
那么你只能在 lambda 函数中知道高度吗? - Math Machine
@MathMachine 是的!这个函数是可靠的,可以正确地给出高度。它可能对许多用例有用。 - Faisal Khan
显示剩余2条评论

0

从Android R(SDK 30+)开始,您可以使用此代码获取状态栏和导航栏的大小

    WindowInsets insets = activity.getWindowManager().getCurrentWindowMetrics().getWindowInsets();
    int statusBarHeight = insets.getInsets(WindowInsetsCompat.Type.statusBars()).top; //in pixels
    int navigationBarHeight = insets.getInsets(WindowInsetsCompat.Type.navigationBars()).bottom; //in pixels

0
    fun Context.isSoftNavigationBarAvailable(): Boolean {
        val navBarInteractionModeId = resources.getIdentifier(
                  "config_navBarInteractionMode",
                  "integer",
                  "android"
        )
        if (navBarInteractionModeId > 0 && resources.getInteger(navBarInteractionModeId) > 0) {
            // nav gesture is enabled in the settings
            return false
        }
        val appUsableScreenSize = Point()
        val realScreenSize = Point()
        val defaultDisplay = (getSystemService(Context.WINDOW_SERVICE) as WindowManager).defaultDisplay
        defaultDisplay.getSize(appUsableScreenSize)
        defaultDisplay.getRealSize(realScreenSize)
        return appUsableScreenSize.y < realScreenSize.y }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接