Android DisplayMetrics在ICS上返回不正确的屏幕像素大小

24

我已经尝试过这个……

DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
int fullscreenheight = metrics.heightPixels;
int fullscreenwidth = metrics.widthPixels;

并且...

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

Gnex的分辨率为720×1280。无论是横屏还是竖屏,返回的宽度/高度结果从未为1280。我认为这可能与Ice Cream Sandwich中的屏幕导航栏有关,因此我使用以下方法隐藏它:

getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);

然后启动一个线程,持续记录屏幕大小的高度/宽度。即使ICS导航栏完全消失...屏幕大小也不会报告1280值。我得到的数字如下:

width  = 720
height = 1184

在ICS中如何获取真实的设备屏幕分辨率?

我需要这个值的原因是因为我的应用程序播放视频,当设备处于横向方向时,我希望视频占据整个屏幕。现在我知道你在想什么,为什么不只给videoview的高度/宽度设置“match_parent”的值呢?原因是因为我的视频有多个宽高比,我希望能够根据屏幕的整个宽度计算正确的视频大小。

6个回答

20

我发现了这个只针对ICS的隐藏宝藏......如果你的目标API高于ICS,请查看下面Chris Schmich的评论。

如何在Android ICS版本上隐藏和显示导航栏

万一链接失效....这是如何获取实际设备屏幕尺寸的方法.....

Display display = getWindowManager().getDefaultDisplay();     
Method mGetRawH = Display.class.getMethod("getRawHeight");
Method mGetRawW = Display.class.getMethod("getRawWidth");
int rawWidth = (Integer) mGetRawW.invoke(display);
int rawHeight = (Integer) mGetRawH.invoke(display);

编辑(11/19/12)

上述代码在Android 4.2上不会起作用,会抛出异常......我还没有找到一种方法来获取Android 4.2设备的全屏大小。当我找到时,我会编辑这个答案,但现在,你应该考虑针对Android 4.2编写备用方案!


2
  • 为什么谷歌让我变得这么原始?
- dell116
非常感谢,这样可以省去我很多麻烦。 - Diljeet
15
在Android 4.2(API 17)及以上版本中,您可以使用Display.getRealMetrics来获取实际物理显示指标。我确认这在我的三星Galaxy Nexus上与Jelly Bean(4.2.1)一起运作。请参见http://developer.android.com/reference/android/view/Display.html#getRealMetrics(android.util.DisplayMetrics)。 - Chris Schmich
1
请注意,getRawHeight和getRawWidth仅在API 14及以上版本中可用。因此,我们只能在API 14、15和16中使用它们。 - Pascal Dimassimo
我在另一个问题上写了一个答案,使用这个选项和其他选项来获取在API 10+上最佳的显示度量。 - CorayThan
不要使用反射来访问像这样的方法。这样的方法是隐藏的,因为没有保证它们将在未来的版本中存在或在版本之间返回相同的值。 - Jacob Tabak

20

根据Ahmed的答案,这是没有错误的完整代码:

    int width = 0, height = 0;
    final DisplayMetrics metrics = new DisplayMetrics();
    Display display = getWindowManager().getDefaultDisplay();
    Method mGetRawH = null, mGetRawW = null;

    try {
        // For JellyBean 4.2 (API 17) and onward
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) {
            display.getRealMetrics(metrics);

            width = metrics.widthPixels;
            height = metrics.heightPixels;
        } else {
            mGetRawH = Display.class.getMethod("getRawHeight");
            mGetRawW = Display.class.getMethod("getRawWidth");

            try {
                width = (Integer) mGetRawW.invoke(display);
                height = (Integer) mGetRawH.invoke(display);
            } catch (IllegalArgumentException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    } catch (NoSuchMethodException e3) {  
        e3.printStackTrace();
    }

11
你可以使用getRealSize方法获取屏幕分辨率。它在API 17及以上版本中得到了官方支持,但实际上自API 14版本就已存在于SDK中。如果你使用的是API 17或更高版本的SDK平台,则可以正常访问该方法,并忽略有关仅在API 17中可用的警告。
/**
 * Gets the device's native screen resolution rotated
 * based on the device's current screen orientation.
 */
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) //To remove warning about using
                                               //getRealSize prior to API 17
private Point screenResolution() {
    WindowManager windowManager =
        (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
    Display display = windowManager.getDefaultDisplay();
    Point screenResolution = new Point();

    if (Build.VERSION.SDK_INT < 14)
        throw new RuntimeException("Unsupported Android version.");
    display.getRealSize(screenResolution);

    return screenResolution;    
}

我已在真实的 Android 5.0.2 设备和运行 4.1.1 的模拟器上测试过(可能还有其他设备)。

感谢 benc评论中指出这一点


此方法已在API级别31中被弃用。 您可以使用WindowManager#getCurrentWindowMetrics()代替。 - Mikhail Valuyskiy

6

试试这个

    final DisplayMetrics metrics = new DisplayMetrics(); 
    Display display = getWindowManager().getDefaultDisplay();     
    Method mGetRawH = null,mGetRawW = null;

    try {
                    // For JellyBeans and onward
        if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN){
            display.getRealMetrics(metrics);

            realWidth = metrics.widthPixels;
            realHeight = metrics.heightPixels;
        }else{
            mGetRawH = Display.class.getMethod("getRawHeight");
            mGetRawW = Display.class.getMethod("getRawWidth");

            try {
                realWidth = (Integer) mGetRawW.invoke(display);
                realHeight = (Integer) mGetRawH.invoke(display);
            } catch (IllegalArgumentException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

1
在我的有限测试中,即使在4.0设备上,getRealMetrics()也可以给出正确的结果,这是出乎意料的。值得注意的是,getRealMetrics返回正确的DPI,而其他获取DisplayMetrics的方法可能会返回虚假数据。(使用其他方法时,我的S4声称自己是一个mpdi设备!) - benkc

3
public static Point getRealSize(Display display) {
        Point outPoint = new Point();
        Method mGetRawH;
        try {
            mGetRawH = Display.class.getMethod("getRawHeight");
            Method mGetRawW = Display.class.getMethod("getRawWidth");
            outPoint.x = (Integer) mGetRawW.invoke(display);
            outPoint.y = (Integer) mGetRawH.invoke(display);
            return outPoint;
        } catch (Throwable e) {
            return null;
        }
    }

    public static Point getSize(Display display) {
        if (Build.VERSION.SDK_INT >= 17) {
            Point outPoint = new Point();
            DisplayMetrics metrics = new DisplayMetrics();
            display.getRealMetrics(metrics);
            outPoint.x = metrics.widthPixels;
            outPoint.y = metrics.heightPixels;
            return outPoint;
        }
        if (Build.VERSION.SDK_INT >= 14) {
            Point outPoint = getRealSize(display);
            if (outPoint != null)
                return outPoint;
        }
        Point outPoint = new Point();
        if (Build.VERSION.SDK_INT >= 13) {
            display.getSize(outPoint);
        } else {
            outPoint.x = display.getWidth();
            outPoint.y = display.getHeight();
        }
        return outPoint;
    }

1

在某些设备上,例如平板电脑,导航栏根本无法隐藏(source,请参见“系统UI可见性控件”部分),因为没有硬件按钮作为备份。但是,如果您已经成功隐藏了该栏,则可以创建一个全屏视图,并使用getWidth()和getHeight()请求其大小。

据我所知,在所有ICS设备上获取屏幕尺寸的可靠方法并不存在。


一定有方法可以做到这一点。ICS的YouTube应用程序以某种方式吹走了ICS导航栏,并使videoview成为整个屏幕的宽度。 - dell116
这取决于设备,在使用ICS平板电脑时,该条可能会被强制隐藏(控件将被隐藏),但并未消失。 - user1340450
Stuart,我无法确认你是否能够在运行ICS的平板电脑上彻底消除屏幕上的OS导航栏,但即使你所说的是真的...隐藏OS导航栏是设备相关的...我不知道为什么Google会故意阻碍开发人员获取设备的确切尺寸。这有什么意义呢?顺便说一句...请不要把这看作是对你回答的攻击。感谢讨论! - dell116
不用担心,我也很感谢这次讨论,我同意为Android提供一种请求屏幕分辨率的方法是有意义的。最近我自己也想使用这个功能,但当我搜索如何实现时,我找不到相关信息。如果您想验证某些设备上无法隐藏导航栏的情况,我已经在我的原始答案中添加了一个链接。 - user1340450

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