Android 获取屏幕高度的坑

1,841 阅读1分钟

最近在做一个项目,绘制一个自定义View,距离屏幕底部 XXdp,在占满全屏的父布局里的 onLayout() 回调方法中对该自定义 View 进行位置布局,Y 轴的坐标算法如下:

val mViewYPosition = Utils.getScreenHeight() - mView.measureHeight - bottomMargin

其中获取手机屏幕高度的工具方法如下:

private int sScreenHeight = 0

public static int getScreenHeight() {
    if (sScreenHeight != 0) {
        return sScreenHeight;
    }
    WindowManager wm = (WindowManager) mAppContext.getSystemService(Context.WINDOW_SERVICE);
    if (wm != null && wm.getDefaultDisplay() != null) {
        DisplayMetrics outMetrics = new DisplayMetrics();
        Display display = wm.getDefaultDisplay();
        display.getMetrics(outMetrics);
        switch (display.getRotation()) {
            case Surface.ROTATION_0:
            case Surface.ROTATION_180://fall through
                sScreenHeight = outMetrics.heightPixels;
                sScreenWidth = outMetrics.widthPixels;
                break;
            case Surface.ROTATION_90:
            case Surface.ROTATION_270://fall through
                sScreenHeight = outMetrics.widthPixels;
                sScreenWidth = outMetrics.heightPixels;
                break;
        }
        return sScreenHeight;
    } else {
        return 1080;
    }
}

实际测试发现,在不同安卓机型上该自定义 View 距离底部的高度是明显不一致的。

最后通过排查发现,不同机型的屏幕高度获取方式是不一样的:

  • 比如在小米 note3(Android 9, 物理导航栏) 这种机型,screenHeight 就是最终的屏幕高度
  • 而小米10的最终屏幕高度是 screenHeight + statusBarHeight + navigationBarHeight

这里关于手机屏幕尺寸的发展史可以看这篇文章,写得很详细 《聊聊获取屏幕高度这件事》

厂商从未停止魔改的步伐,如果每次出新尺寸的屏幕都要去适配一下,是很费力的。

因此,最佳做法是直接获取当前这个全屏父布局的高度,来间接得到准确的 ScreenHeight。

以下列出错误方式和准确方式:

  • 错误方式
var totalScreenHeight = DeviceTool.getStatusBarHeight() + DeviceTool.getScreenHeight() 
+ DeviceTool.getNavigationBarHeight() //错误方式
  • 以不变应万变的解决方案
var totalScreenHeight = parentView.measuredHeight //正确方式(注意获取measureHeight 的时机,此处只是示例)

另外,这里提供一种查看屏幕分辨率的快捷命令:

adb shell wm size

打印如下:

image.png