【问题标题】:Get the screen height in Android获取Android中的屏幕高度
【发布时间】:2013-06-27 21:50:51
【问题描述】:

如何在 Android 中获取屏幕的可用高度?我需要高度减去状态栏/菜单栏或屏幕上可能出现的任何其他装饰,我需要它适用于所有设备。另外,我需要在 onCreate 函数中知道这一点。我知道以前有人问过这个问题,但我已经尝试过他们的解决方案,但都没有奏效。以下是我尝试过的一些事情:

我已经在 API 7 - 17 上测试了这段代码。不幸的是,在 API 13 上,底部水平和垂直都有额外的空间,而在 API 10、8 和 7 上,底部水平和垂直都没有足够的空间. (我没有在过时的 API 上进行测试):

Display display = getWindowManager().getDefaultDisplay();
DisplayMetrics metrics = new DisplayMetrics();
display.getMetrics(metrics);
screenWidth = metrics.widthPixels;
screenHeight = metrics.heightPixels;

TypedValue tv = new TypedValue();
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
{
    if (getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true))
        screenHeight -= TypedValue.complexToDimensionPixelSize(tv.data,getResources().getDisplayMetrics());
}

int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0)
    screenHeight -= getResources().getDimensionPixelSize(resourceId);

这里不考虑状态栏/菜单栏:

Display display = getWindowManager().getDefaultDisplay();
screenWidth = display.getWidth();
screenHeight = display.getHeight();

这也不行:

Point size = new Point();
getWindowManager().getDefaultDisplay().getSize(size);
screenWidth = size.x;
screenHeight = size.y;

也不是这样:

Point size = new Point();
getWindowManager().getDefaultDisplay().getRealSize(size);
screenWidth = size.x;
screenHeight = size.y;

这不起作用:

Display display = getWindowManager().getDefaultDisplay();
DisplayMetrics metrics = new DisplayMetrics();
display.getMetrics(metrics);
// since SDK_INT = 1;
screenWidth = metrics.widthPixels;
screenHeight = metrics.heightPixels;
try
{
    // used when 17 > SDK_INT >= 14; includes window decorations (statusbar bar/menu bar)
    screenWidth = (Integer) Display.class.getMethod("getRawWidth").invoke(display);
    screenHeight = (Integer) Display.class.getMethod("getRawHeight").invoke(display);
}
catch (Exception ignored)
{
    // Do nothing
}
try
{
    // used when SDK_INT >= 17; includes window decorations (statusbar bar/menu bar)
    Point realSize = new Point();
    Display.class.getMethod("getRealSize", Point.class).invoke(display, realSize);
    screenWidth = realSize.x;
    screenHeight = realSize.y;
}
catch (Exception ignored)
{
    // Do nothing
}

然后我使用以下代码从屏幕高度中减去状态栏和菜单栏的高度:

int result = 0;
int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0)
    result = getResources().getDimensionPixelSize(resourceId);
screenHeight -= result;
result = 0;
if (screenHeight >= screenWidth)
    resourceId = getResources().getIdentifier("navigation_bar_height", "dimen", "android");
else
    resourceId = getResources().getIdentifier("navigation_bar_height_landscape", "dimen", "android");
if (resourceId > 0)
    result = getResources().getDimensionPixelSize(resourceId);
screenHeight -= result;

在 API 17 上,它可以正确计算纵向状态栏和菜单栏的高度,但不能正确计算横向。在 API 10 上,它返回 0。我需要它在所有设备或最低 API 7 上理想地工作。

【问题讨论】:

  • 如果你在 onCreate 方法中真的需要精确的尺寸,那你就做错了。使用全局布局侦听器并在布局阶段完成时运行您的操作是正确的方法,例如@Carnal 答案。在全局布局回调中,您应该在视图上使用 getMessureadHeight 而不是 getHeight。
  • @DanBray - 请查看我提出的解决方案。它绝对有效。
  • 使用OnGlobalLayoutListener 或通过将Runnable 发布到根视图的消息队列来延迟获取尺寸的任何方法都应该有效。
  • 我会得到装饰视图并根据 DecorView 进行所有计算

标签: java android android-layout layout screen


【解决方案1】:

如果你想要以像素为单位的显示尺寸,你可以使用getSize:

Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
int width = size.x;
int height = size.y;

如果您不在Activity 中,您可以通过WINDOW_SERVICE 获得默认显示:

WindowManager wm = (WindowManager) ctx.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
display.getSize(size);
int width = size.x;
int height = size.y;

在引入 getSize 之前(在 API 级别 13 中),您可以使用现在已弃用的 getWidth 和 getHeight 方法:

Display display = getWindowManager().getDefaultDisplay(); 
int width = display.getWidth();  // deprecated
int height = display.getHeight();  // deprecated

引用自: Get screen dimensions in pixels

【讨论】:

    【解决方案2】:

    工作解决方案:

    创建两个虚拟视图:

     <View
        android:id="@+id/top"
        android:layout_height="0dp"
        android:layout_width="match_parent"
        android:layout_alignParentTop="true" />
    
    <View
            android:id="@+id/bottom"
            android:layout_height="0dp"
            android:layout_width="match_parent"
            android:layout_alignParentBottom="true" />
    

    现在,您应该在这两个视图上调用 getLocationOnScreen(int []) 以接收它们的位置。该函数返回一个由 2 个整数组成的数组。第一个是 x,第二个是 y。我们只需要 y。另请注意,只有在创建所有视图并退出 onCreate 方法后才会返回正确的值。

    我在从 viewpager 调用的常规片段上测试了此代码。

    代码在我的片段的onCreateView 方法中。我仍然必须使用postDelayed 来获得正确的值。

    final View top = (View) view.findViewById(R.id.top);
        final View bottom = (View) view.findViewById(R.id.bottom);
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
    
                int topLoc[] = new int[2];
                top.getLocationOnScreen(topLoc);
                int BottomLoc[] = new int[2];
                bottom.getLocationOnScreen(BottomLoc);
                Log.d(Constants.debug, "topY: "+ topLoc[1]+" BottomY:" + BottomLoc[1]);
            }
        },4000);
    

    我有一个 Nexus 4。

    在常规模式下(显示状态栏和软按钮):

    07-05 02:28:23.367      565-565/com.torcellite.xx D/xx: topY: 50 BottomY:1182
    

    在全屏模式下(不显示状态栏或软按钮):

    07-05 02:29:17.360      707-707/com.torcellite.xx D/xx: topY: 0 BottomY:1280
    

    你现在要做的就是减去。

    【讨论】:

    • 你能发布 logcat 吗?如果它是一个活动,请尝试将我的代码放入onResume
    • 我想我知道它为什么会崩溃。顶部和底部的两个视图必须位于您在活动中设置内容视图的同一个 XML 文件中。因此,如果它的main_activity.xml 视图进入该 XML 文件。不是新的。
    • 好的,那您不是在设置内容视图吗?然后,您应该在代码中动态扩展这些视图。
    • 您需要将视图添加到layout
    【解决方案3】:

    用于展示

    DisplayMetrics displaymetrics = new DisplayMetrics();
    getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
    int height = displaymetrics.heightPixels;
    int width = displaymetrics.widthPixels;
    

    状态栏

    public int getStatusBarHeight() {
            int result = 0;
            int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
            if (resourceId > 0) {
                result = getResources().getDimensionPixelSize(resourceId);
            }
            return result;
        }
    

    【讨论】:

    • 这是我尝试过的方法之一,但它不适用于所有设备。我在我的问题中展示了这一点。
    • @DanBray - 请看看我的解决方案,它适用于所有设备
    【解决方案4】:

    我没有尝试过不同的 API,但我正在使用这些值来确定屏幕键盘是否启动。也许你可以试试这个和类似的宽度来获得你需要的东西?

    Rect r = new Rect();
    view.getWindowVisibleDisplayFrame(r);
    int
        screenHeight = view.getRootView().getHeight(), // height of the entire screen
        appHeight = r.bottom - r.top, // height of the entire app
        statusBarHeight = r.top, // height of the statusbar
        pageHeight = view.getHeight(), // height of the app without title
        appTitleHeight = appHeight - pageHeight, // height of the only the app title
        topHeight = statusBarHeight + appTitleHeight;
    

    【讨论】:

      【解决方案5】:
      final View view = findViewById(R.id.root);
      ViewTreeObserver vto = view.getViewTreeObserver();
      vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
          @Override
          public void onGlobalLayout() {
              // calculate the height in here...
      
              ViewTreeObserver vto = view.getViewTreeObserver();
              vto.removeGlobalOnLayoutListener(this);
          }
      });
      

      onCreate 中使用这个监听器(从 api 1 开始可用)。您需要将 id @+id/root 分配给 xml 布局中的父级。 size 不可能返回 0 的结果,因为只要布局在视图中定位,此侦听器就会进行回调。

      【讨论】:

      • 如果我使用的是 XML 文件,这可能会起作用。我正在做没有 XML 文件的布局。实际上,我的整个程序有 0 个 XML 文件,因为我希望它动态工作。
      • 我使用final View view = getWindow().getDecorView().getRootView(); 而不是final View view = findViewById(R.id.root); 获得了视图,不幸的是,我仍然无法获得减去任何装饰的屏幕高度。 screenHeight = view.getMeasuredHeight();screenHeight = view.getHeight(); 没有状态栏或菜单栏的不要给出高度。
      • 这在 onCreate 中不起作用。这仅在布局展开后触发,在 onCreate 执行后发生。
      • 在写你不理解的东西之前,你应该阅读一下 OnGlobalLayoutListener 并给我投票!
      【解决方案6】:
      Display currentDisplay = getWindowManager().getDefaultDisplay();
              float dw = currentDisplay.getWidth();
              float dh = currentDisplay.getHeight();
      

      dh 会给你屏幕高度。

      【讨论】:

      • 这个是我试过的,但是没有考虑到状态栏/菜单栏。我在我的问题中展示了这一点。
      • switch (displayMetrics.densityDpi) {case displayMetrics.DENSITY_HIGH: statusBarHeight = HIGH_DPI_STATUS_BAR_HEIGHT;休息;案例 DisplayMetrics.DENSITY_MEDIUM:statusBarHeight = MEDIUM_DPI_STATUS_BAR_HEIGHT;休息;案例 DisplayMetrics.DENSITY_LOW:statusBarHeight = LOW_DPI_STATUS_BAR_HEIGHT;休息;默认值:statusBarHeight = MEDIUM_DPI_STATUS_BAR_HEIGHT; } 使用这个 switch case,你会得到不同屏幕密度的状态栏高度。
      【解决方案7】:

      如何设置一个子类视图作为 Activity 的根。让这个视图填满屏幕(它不会越过状态栏)并覆盖onSizeChanged()。存储这些值并为它们编写一个 getter。

      【讨论】:

        【解决方案8】:

        它可能无法回答您的问题,但知道它可能很有用(我是 当我遇到这个问题时自己寻找它)如果你需要一个 视图的尺寸,但您的代码在其布局具有时正在执行 尚未布置(例如在 onCreate() 中),您可以设置一个 ViewTreeObserver.OnGlobalLayoutListener 与 View.getViewTreeObserver().addOnGlobalLayoutListener() 并把 那里需要视图尺寸的相关代码。听者的 布局完成后会调用回调。

        礼貌-Francesco Feltrinelli

        您可以尝试这样做。

        【讨论】:

          【解决方案9】:

          获取活动加载的根布局的高度。如果它没有填满屏幕,请将其放在另一个布局中,其高度属性为 fill_parent。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2011-06-12
            • 1970-01-01
            • 2010-11-25
            • 1970-01-01
            • 2020-05-14
            • 2011-10-31
            • 2011-09-25
            相关资源
            最近更新 更多