一、 前言

android 4.4(sdk 19)之后,获取屏幕高度需要考虑底部导航栏等decor。网上很多方案是没有考虑这一点的,因此获取到的屏幕高度小于实际高度,误导开发者。


二、 错误方案

列举几种常见的获取出来高度可能小于实际高度的方案:

DisplayMetrics dm = getApplicationContext().getResources().getDisplayMetrics(); int screenWidth = dm.widthPixels; int screenHeight = dm.heightPixels; 
Display display = getWindowManager().getDefaultDisplay();int screenWidth  = display.getWidth();int screenHeight = display.getHeight();
WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);int screenWidth = wm.getDefaultDisplay().getWidth();int screenHeight = wm.getDefaultDisplay().getHeight();
DisplayMetrics outMetrics = new DisplayMetrics();getWindowManager().getDefaultDisplay().getMetrics(outMetrics);int screenWidth = outMetrics.widthPixels;int screenHeight = outMetrics.heightPixels;

三、 正确方案

以下是供参考的获取完整高度的方案:

WindowManager windowManager = (WindowManager) getApplication().getSystemService(Context.WINDOW_SERVICE);Display display = windowManager.getDefaultDisplay();Point outPoint = new Point();if (Build.VERSION.SDK_INT >= 19) {// 可能有虚拟按键的情况display.getRealSize(outPoint);} else {// 不可能有虚拟按键display.getSize(outPoint);}int mRealSizeWidth;//手机屏幕真实宽度int mRealSizeHeight;//手机屏幕真实高度mRealSizeHeight = outPoint.y;mRealSizeWidth = outPoint.x;
DisplayMetrics metric = new DisplayMetrics();getWindowManager().getDefaultDisplay().getRealMetrics(metric);int width = metric.widthPixels; // 宽度(PX)int height = metric.heightPixels; // 高度(PX)

四、 源码解读

以上方法的区别在于"getRealSize"和"getRealMetrics",查看源码:

1.getMetrics:

    /**     * Gets display metrics that describe the size and density of this display.     * The size returned by this method does not necessarily represent the     * actual raw size (native resolution) of the display.     * 

* 1. The returned size may be adjusted to exclude certain system decor elements * that are always visible. *

* 2. It may be scaled to provide compatibility with older applications that * were originally designed for smaller displays. *

* 3. It can be different depending on the WindowManager to which the display belongs. *

* - If requested from non-Activity context (e.g. Application context via * {@code (WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE)}) * metrics will report the size of the entire display based on current rotation and with * subtracted system decoration areas. *

* - If requested from activity (either using {@code getWindowManager()} or * {@code (WindowManager) getSystemService(Context.WINDOW_SERVICE)}) resulting metrics will * correspond to current app window metrics. In this case the size can be smaller than physical * size in multi-window mode. *

* * @param outMetrics A {@link DisplayMetrics} object to receive the metrics. */
public void getMetrics(DisplayMetrics outMetrics) { synchronized (this) { updateDisplayInfoLocked(); mDisplayInfo.getAppMetrics(outMetrics, getDisplayAdjustments()); } }
  • 包含decor时,返回的size可能不准确
  • 老式机型下可能不准确
  • 可能因WindowManager而改变

2.getRealSize:

    /**     * Gets the real size of the display without subtracting any window decor or     * applying any compatibility scale factors.     * 

* The size is adjusted based on the current rotation of the display. *

* The real size may be smaller than the physical size of the screen when the * window manager is emulating a smaller display (using adb shell wm size). *

* * @param outSize Set to the real size of the display. */
public void getRealSize(Point outSize) { synchronized (this) { updateDisplayInfoLocked(); outSize.x = mDisplayInfo.logicalWidth; outSize.y = mDisplayInfo.logicalHeight; } }
  • 获取的size没有减去任何decor或者考虑缩放因素
  • 使用"adb shell wm size"可以查看设备的物理尺寸

3.getRealMetrics:

    /**     * Gets display metrics based on the real size of this display.     * 

* The size is adjusted based on the current rotation of the display. *

* The real size may be smaller than the physical size of the screen when the * window manager is emulating a smaller display (using adb shell wm size). *

* * @param outMetrics A {@link DisplayMetrics} object to receive the metrics. */
public void getRealMetrics(DisplayMetrics outMetrics) { synchronized (this) { updateDisplayInfoLocked(); mDisplayInfo.getLogicalMetrics(outMetrics, CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null); } }
  • 基于getRealSize实现

五、 参考文献

  • Android 获取屏幕高和宽(不包含/包含虚拟按键),状态栏的高度
  • Android获取真正准确的分辨率,拒绝那些瞎扯乱混的文章

更多相关文章

  1. 新浪OAuth同步方案(测试成功)
  2. Android(安卓)PopupWindow与ListView配合使用
  3. Android滑动组件----RecyclerView并且实现点击事件(2)
  4. Android权限系统(一):开机获取权限信息
  5. Android(安卓)- 判断当前网络环境、隐藏软键盘、动态监测及获取
  6. Android获取系统cpu信息,内存,版本,电量等信息
  7. ActionBar简单使用介绍和Tab切换的应用
  8. Android通过包名获取应用信息
  9. Android中如何获取字符或者字符串的宽度

随机推荐

  1. Android AIDL机制
  2. Android尺寸标注设计大全和Android切图规
  3. Android 透明式系统栏设计
  4. 滚动条~~~xml方式(一)
  5. Android和iOS对矢量图片的支持
  6. Android学习手记:第一个应用程序!
  7. Android Dialog使用举例
  8. ART:Android 摆脱卡顿的希望?
  9. 详解Android技术的生态系统及其安全机制
  10. 【Android每周专题】网络编程