如何以编程方式一劳永逸地获取android屏幕尺寸?


132

如何以触摸事件和查看测量/布局所使用的单位以编程方式找出屏幕尺寸?换句话说,我想要屏幕右下角的坐标,在触摸事件' getRawX()/getRawY()和所使用的坐标系中 View.getLocationOnScreen()

我不愿意将所需的事件/视图单位称为“像素”,因为我的手机在各种模式下显然都存在“像素”的几种概念,而且它们并没有形成一致的故事。

我认为这已被要求,并回答了很多计算器和其他地方,但没有答案我的手机上实际工作(DROID 4的Android 4.1.2)在所有模式:

(哇!)

这适用于需要运行的库代码,而不管应用程序是否处于“屏幕兼容模式”(即清单中的targetSdkVersion <= 10),而且我也不希望对位置,大小做任何假设,或状态栏或任何其他类似的屏幕装饰的存在。


这是事实:

  1. 我的手机(运行android 4.1.2的droid 4)的物理像素为540x960,即彩色发光点很少。

  2. 如果应用程序处于屏幕兼容模式,则从观看触摸事件和查看测量值开始,屏幕尺寸的单位为360x640;如果应用程序处于屏幕兼容模式,则屏幕尺寸为540x960。这些是我需要以编程方式找到的数字,而不会为触摸事件或视图带来麻烦,但是我很难找到任何会返回这些数字的API。

  3. 以各种方式获得的Display和DisplayMetrics对象都声称屏幕尺寸为540 x 960“像素”(无论是否在屏幕兼容模式下)。具体而言,以下所有内容始终都是540x960:DisplayMetrics。{width,height}像素,Display.getSize(),Display.getRealSize(),Display.get {Width,Height}(),

  4. 以各种方式获得的配置对象都表示screen {Width,Height} Dp = 360x614(无论是否处于屏幕兼容模式)。我不认为这代表了整个屏幕,因为宽高比是错误的。(我认为这是整个屏幕减去状态栏;我需要整个屏幕。)我认为可以说整个屏幕为360x640 dp,尽管我不知道有返回该640的API。

  5. 通过各种方式获得的DisplayMetrics表示,在屏幕兼容模式下,“密度”为1.0f,在非屏幕兼容模式下为1.5f。

  6. 该活动 getWindow().getAttributes().{width,height} 没有帮助,因为它通常包含MATCH_PARENT 而非实际大小。但是我显然可以从活动的答案中得到所需的答案 getWindow().getDecorView().getMeasured{Width,Height}() (这实际上令人惊讶,因为活动窗口的decorView 看起来好像不占用整个屏幕;看起来好像是在减去状态栏占用了屏幕)。但是我不想依赖于此,因为如果窗口调整了大小(出现了软键盘?有人在调用window.setAttributes()?或者也许我根本不在活动中),这显然就是全部了。错误。

我了解以下公式应该成立:像素= dp *密度当处于屏幕兼容模式时,这似乎与所有报告的数字(上述(3),(4),(5))一致:540x960 = 360x640 * 1.5但是在屏幕兼容模式下,它不会累加:540x960!= 360x640 * 1因此,有些问题。

我认为,最简单的解释是,在屏幕兼容模式下,上面(3)中列出的方法只是对“像素”给出了错误的答案-也就是说,它们打算返回360x640“像素”,但它们是错误的传回540x960。但是,也许还有其他的观察方法。

无论如何,从上面的拼图中获得与模式无关的期望数字无疑是一个棘手的难题。我发现一种在两种模式下都可以在我的手机上运行的方法,但是它非常circuit回,它依赖于两个看起来仍然有些不稳定的假设(如下面的代码注释中所述)。

这是我的食谱:

/** get screen size in "pixels", i.e. touchevent/view units.
* on my droid 4, this is 360x640 or 540x960
* depending on whether the app is in screen compatibility mode
* (i.e. targetSdkVersion<=10 in the manifest) or not. */
public void getScreenSizePixels(int widthHeightInPixels[/*2*/])
{
    Resources resources = getResources();
    Configuration config = resources.getConfiguration();
    DisplayMetrics dm = resources.getDisplayMetrics();
    // Note, screenHeightDp isn't reliable
    // (it seems to be too small by the height of the status bar),
    // but we assume screenWidthDp is reliable.
    // Note also, dm.widthPixels,dm.heightPixels aren't reliably pixels
    // (they get confused when in screen compatibility mode, it seems),
    // but we assume their ratio is correct.
    double screenWidthInPixels = (double)config.screenWidthDp * dm.density;
    double screenHeightInPixels = screenWidthInPixels * dm.heightPixels / dm.widthPixels;
    widthHeightInPixels[0] = (int)(screenWidthInPixels + .5);
    widthHeightInPixels[1] = (int)(screenHeightInPixels + .5);
}

有没有更好/更清洁的方法来查找屏幕尺寸?


29
+1个好问题,并显示出很多研究成果。
Alex Gittemeier

1
@Don在docs中,说明了兼容模式将停止在较旧的设置上执行“缩放以适合”操作。但是,它并没有明确解释“它是如何工作的”,从您的观察来看,我认为它们只是关闭了密度缩放,即:1px变为1dp。可能是此更改仅在渲染部分,而DisplayMetrics从未更新过此类更改。像这样的问题已经提起。
SD

@ user117-有趣。那么部分 DisplayMetrics拿到了在least--密度变成1.0更新。但是,看来widthPixels / heightPixels并没有改变以匹配。关于引用的问题,看来行为已恢复为3.1行为(即,我看到heightPixels 包含状态栏...但似乎使用的单位错误)
Don Hatch

@DonHatch谢谢,亲切的-我实际上是想对一个深思熟虑的问题给予表扬,奇怪的是,在StackExchange上不那么受欢迎-请注意,这个比“真实的”问题如何在答案中什么都没有得到,谈到(低)受众在该主题上的知识质量。现在,我可能因自己的问题因“不真实”而被一个接一个地关闭而感到不安,幽默感可能使我不满意,但看起来好像有“尼基”的问题确实是答案这一切在这里发生了...当然,我赞成您的:)
mlvljr 2013年

顺便说一句!以下是我的怀疑:michael.richter.name/blogs/…(尤其是见他的观点(1),一个快速制定的答案-实际上就是这个问号!)。无论如何,纽约快乐(11分钟内就来了)!:)
mlvljr 2013年

Answers:


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

现在,您可以以像素为单位来测量屏幕尺寸,这是比厘米更好的测量单位,因为所有按钮,文本视图等均以该单位进行测量。那是我通常使用的


3
根据Op(特别是第3点)的说法,在屏幕兼容模式下这不正确吗?
汤姆(Tom)

9

通过使用DisplayMetrics,您可以获取任何设备屏幕的高度和宽度。请注意,宽度和高度对旋转敏感。这是代码。

DisplayMetrics metrics; 
int width = 0, height = 0;

在您的onCreate方法中

 metrics = new DisplayMetrics();        
 getWindowManager().getDefaultDisplay().getMetrics(metrics);

 height = Math.min(metrics.widthPixels, metrics.heightPixels); //height
 width = Math.max(metrics.widthPixels, metrics.heightPixels); //width

试试这个。


2
不,正如我在(3)中所述,指标。{width,height}像素在屏幕兼容模式下无法给出正确的答案。
唐·哈奇

我还发现:似乎是Litemetrics.heightPixels可能会给出宽度,以防屏幕旋转,反之亦然!
JohnyTex19年

8

在您的#6中,您注意到DecorView似乎提供了您想要的东西,但您认为这是不可能的。我相信那将尽你所能。根据文档Window.getDecorView

检索顶级窗口装饰视图(包含标准窗口框架/装饰以及其中的客户端内容),可以将其作为窗口添加到窗口管理器中。

状态栏是此处提到的窗户装饰的一部分。软件键盘和其他覆盖图将收到自己的窗口,因此它们不应干扰相关的值。正确的是显示指标不正确,但是如果您的应用程序是全屏显示,则应始终是通过兼容性转换器过滤的全屏尺寸。其他应用程序将无法访问您的应用程序的Window,因此您无需担心其他应用程序在不使用时更改属性。

希望有帮助。


5

我应该将此作为评论,但我没有代表。
这可能不是一个完全正确的答案,但是当我在DisplayMetrics方法中切换高度和宽度时,我得到了尺寸。

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

正如我说的那样,这可能不正确,但我不知道为什么,但这对我有用。


我相信这是因为屏幕旋转了。
JohnyTex19年

那不信任我。
abhyudayasrinet


3

我已经用毕达哥拉斯定理找到了Android手机/平板电脑屏幕的对角线大小,同样的原理可以应用于iPhone或黑莓手机屏幕。

DisplayMetrics met = new DisplayMetrics();                
this.getWindowManager().getDefaultDisplay().getMetrics(met);// get display metrics object
String strSize = 
new DecimalFormat("##.##").format(Math.sqrt(((met.widthPixels / met.xdpi) *
(met.widthPixels / met.xdpi)) +
((met.heightPixels / met.ydpi) * (met.heightPixels / met.ydpi))));
// using Dots per inches with width and height

毕达哥拉斯一定是个天才,他这么多年前就知道智能手机编程:p


1

我使用以下方法获取设备的宽度:

public static int getDeviceWidth(Context context){
    WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
    Display display = wm.getDefaultDisplay();
    int width=display.getWidth();
    return width;
}

不建议使用此方法。请使用displaymetrics方法。
西蒙

0

我认为此功能将帮助您简单地获取Android屏幕尺寸的宽度和高度。该函数以整数数组形式返回宽度和高度,如下所示

private int[] getScreenSIze(){
        DisplayMetrics displaymetrics = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
        int h = displaymetrics.heightPixels;
        int w = displaymetrics.widthPixels;

        int[] size={w,h};
        return size;

    }

并在您的create方法上输出您的宽度和高度,如下所示

 int[] screenSize= getScreenSIze();
        int width=screenSize[0];
        int height=screenSize[1];
        screenSizes.setText("Phone Screen sizes \n\n  width = "+width+" \n Height = "+height);

下载源代码并在您的android studio上进行测试


0

这对我有用:

int width = Resources.getSystem()。getDisplayMetrics()。widthPixels;

int height = Resources.getSystem()。getDisplayMetrics()。heightPixels;

我用它来更新水平回收站视图中项目的宽度。(根据我的要求)希望它对某人有帮助!


-1

对于Kotlin中的此解决方案,请尝试以下操作:

private fun yourFunction(){
   val metrics = DisplayMetrics()
   windowManager.defaultDisplay.getMetrics(metrics)
   val width = metrics.widthPixels
   val height = metrics.heightPixels
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.