喔…这标题,吓我一跳;

请稍等…

思绪整理中…

Android中, 经常被这些高度绊脚. 完全进入懵逼的状态, 有木有?

请允许我,介绍清楚!

通常情况下, 宽度都是很友好的,但是高度就呵呵, 所以本文只介绍高度的计算.


2018-10-17更新

安卓开发过程中, 经常被状态栏的高度 导航栏的高度 键盘的高度 搞的稀里糊涂. 经过一段时间整理, 似乎找到了比以前更有效的方法,如下:

所有操作只针对Activity (dialog 不行)window,因为Android界面的载体都是window对象:

可视区域

final View decorView = window.getDecorView();
Rect outRect = new Rect();
decorView.getWindowVisibleDisplayFrame(outRect);

//可视区域
outRect.top -> 可视区域顶部的坐标  (也就是状态栏的高度)
outRect.bottom -> 可视区域底部的坐标  (屏幕高度-导航栏-键盘的高度)
public class DecorUtil {

    /**
     * 请勿在dialog中使用
     * <p>
     * 主题的 android:windowTranslucentStatus 属性, 会影响 contentView 的 padding top.
     * <p>
     * 如果设置了 View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN , 那么 contentView 的 padding top 都是 0
     */
    public static void demo(@NonNull final Window window) {
        final View decorView = window.getDecorView();
        int measuredHeight = decorView.getMeasuredHeight();
        if (measuredHeight <= 0) {
            decorView.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
                @Override
                public boolean onPreDraw() {
                    decorView.getViewTreeObserver().removeOnPreDrawListener(this);

                    demo(window);
                    return true;
                }
            });
        } else {
            Rect outRect = new Rect();
            decorView.getWindowVisibleDisplayFrame(outRect);
            L.w("可视区域:" + outRect);

            L.w("屏幕高度:" + measuredHeight);
            if (decorView instanceof ViewGroup) {
                int childCount = ((ViewGroup) decorView).getChildCount();
                if (childCount > 0) {
                    View contentView = ((ViewGroup) decorView).getChildAt(0);
                    L.w("内容高度:" + contentView.getMeasuredHeight() + " p:" + contentView.getPaddingTop());
                }
                if (childCount > 1) {
                    View childView = ((ViewGroup) decorView).getChildAt(1);
                    if (isStatusBar(decorView, childView)) {
                        L.w("状态栏高度:" + childView.getMeasuredHeight());
                    } else if (isNavigationBar(decorView, childView)) {
                        L.w("导航栏高度:" + childView.getMeasuredHeight());
                    } else {
                        L.w("未知:" + childView);
                    }
                }
                if (childCount > 2) {
                    View childView = ((ViewGroup) decorView).getChildAt(2);
                    if (isStatusBar(decorView, childView)) {
                        L.w("状态栏高度:" + childView.getMeasuredHeight());
                    } else if (isNavigationBar(decorView, childView)) {
                        L.w("导航栏高度:" + childView.getMeasuredHeight());
                    } else {
                        L.w("未知:" + childView);
                    }
                }
            }
        }
    }

    private static boolean isStatusBar(@NonNull View decorView, @NonNull View childView) {
        if (childView.getTop() == 0 &&
                childView.getMeasuredWidth() == decorView.getMeasuredWidth() &&
                childView.getBottom() < decorView.getBottom()
                ) {
            return true;
        }
        return false;
    }

    private static boolean isNavigationBar(@NonNull View decorView, @NonNull View childView) {
        if (childView.getTop() > decorView.getTop() &&
                childView.getMeasuredWidth() == decorView.getMeasuredWidth() &&
                childView.getBottom() == decorView.getBottom()
                ) {
            return true;
        }
        return false;
    }
}

通过以上方法, 可以获得:
状态栏高度导航栏高度以及是否显示键盘的高度以及是否显示


已下是旧文

1:DecorView的高度
DecorView的高度代表的是: 整个装饰窗口的高度, 这个高度包括:状态烂的高度和导航栏的高度.(状态栏和导航栏通常叫做装饰窗口, 而ActionBar不属于装饰窗口)

这个高度, 可以代表着整个玻璃屏幕的高度.

获取方式:mActivity.getWindow().getDecorView()


2.Window的RootView的高度
RootView的获取方式:mActivity.getWindow().findViewById(Window.ID_ANDROID_CONTENT);

这个View对应的高度, 可以表示当前应用程序的有效高度.
在没有任何修饰的情况下, 应用程序的高度是去掉状态栏和导航栏后的高度;

也就是 (DecorView的高度)-(状态栏的高度)-(导航栏的高度);

但是,如果你使用:
setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
这个方法, 那么RootView的高度会和DecorView的高度相等;


3:heightPixels的高度
heightPixels 这个高度表示…屏幕有效的高度;;;
什么意思呢?
就是:DecorView的高度去掉导航栏的高度.
这个高度不管你有没有隐藏导航栏, 这个值都不会改变;

获取方式:mActivity.getResources().getDisplayMetrics().heightPixels

所以:
番外:如果你想知道你的手机有没有导航栏:
如果 (DecorView的高度)-(heightPixels) > 0 说明 你的手机有导航栏

番外:如果你想知道你的程序有没有隐藏导航栏:
情况1:设置了SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN属性:
如果 (RootView的高度)-(heightPixels) > 0 说明 显示了导航栏

情况2:没有设置SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN属性:
如果 (RootView的高度+状态栏的高度)-(heightPixels) > 0 说明 显示了导航栏


附加1 获取状态栏的高度
正常情况下: (heightPixels) - (RootView的高度) = 状态栏的高度
但是如果你设置了View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN或者View.SYSTEM_UI_FLAG_HIDE_NAVIGATION属性的话,这种方法就不准确了.

万能,100%准确的方法:

getResources().getDimensionPixelSize(getResources().getIdentifier(“status_bar_height”, “dimen”, “android”));

附加2:获取导航栏的高度
正常情况下: (DecorView的高度) - (heightPixels) = 导航栏的高度
但是如果你设置了View.SYSTEM_UI_FLAG_HIDE_NAVIGATION属性的话,这种方法就不准确了.

万能,100%准确的方法:

getResources().getDimensionPixelSize(getResources().getIdentifier(“navigation_bar_height”, “dimen”, “android”));