¿Cómo obtener el tamaño de la pantalla de Android mediante programación, de una vez por todas?

132

¿Cómo puedo averiguar el tamaño de mi pantalla mediante programación, en las unidades utilizadas por eventos táctiles y Ver medición / diseño? En otras palabras, quiero las coordenadas de la esquina inferior derecha de la pantalla, en el sistema de coordenadas utilizado por los eventos táctiles getRawX()/getRawY()y View.getLocationOnScreen().

Dudo en llamar a las unidades de evento / vista deseadas "píxeles", ya que evidentemente hay varias nociones de "píxeles" en mi teléfono en varios modos, y no se suman a una historia coherente.

Veo que esto se ha preguntado y respondido mucho en stackoverflow y en otros lugares, pero ninguna de las respuestas realmente funciona en mi teléfono (droid 4, android 4.1.2) en todos los modos:

(¡Guau!)

Esto es para el código de biblioteca que debe funcionar independientemente de si la aplicación está en "modo de compatibilidad de pantalla" (es decir, targetSdkVersion <= 10 en el manifiesto) o no, y tampoco quiero hacer suposiciones sobre la posición, el tamaño , o la existencia de la barra de estado o cualquier otra decoración de pantalla similar.


Aquí están los hechos:

  1. mi teléfono (un droid 4 con Android 4.1.2) tiene 540x960 píxeles físicos, es decir, pequeños puntos brillantes de colores.

  2. El tamaño de la pantalla en las unidades deseadas, desde mirar eventos táctiles y Ver mediciones, es 360x640 cuando la aplicación está en modo de compatibilidad de pantalla, 540x960 cuando la aplicación no está en modo de compatibilidad de pantalla. Estos son los números que necesito encontrar mediante programación, sin alterar los eventos táctiles o las Vistas para encontrarlos, pero tengo dificultades extremas para encontrar cualquier API que devuelva estos números.

  3. Los objetos Display y DisplayMetrics obtenidos de varias maneras afirman que el tamaño de la pantalla es de 540x960 "píxeles" (ya sea en modo de compatibilidad de pantalla o no). Para ser específicos, los siguientes dicen 540x960 todo el tiempo: DisplayMetrics. {Width, height} Pixels, Display.getSize (), Display.getRealSize (), Display.get {Width, Height} (),

  4. Todos los objetos de configuración obtenidos de varias maneras dicen pantalla {Ancho, Altura} Dp = 360x614 (ya sea en modo de compatibilidad de pantalla o no). No creo que eso represente toda la pantalla, ya que la relación de aspecto es incorrecta. (Creo que es toda la pantalla menos la barra de estado; necesito toda la pantalla). Creo que es seguro decir que toda la pantalla tiene 360x640 dp, aunque no conozco ninguna API que devuelva esos 640.

  5. DisplayMetrics obtenido de varias maneras dice que la "densidad" es 1.0f cuando está en modo de compatibilidad de pantalla, 1.5f cuando no está en modo de compatibilidad de pantalla.

  6. La actividad getWindow().getAttributes().{width,height} no es útil, ya que generalmente contiene MATCH_PARENT más que los tamaños reales. Pero aparentemente puedo obtener la respuesta deseada de una actividad getWindow().getDecorView().getMeasured{Width,Height}() (lo cual es realmente sorprendente ya que la decoración de la ventana de la actividad no parece estar ocupando toda la pantalla; parece que está ocupando la pantalla menos la barra de estado). Pero no quiero confiar en esto porque si la ventana alguna vez cambia de tamaño (¿aparece un teclado virtual? ¿Alguien que llama a window.setAttributes ()? incorrecto.

Entiendo que se supone que debe contener la siguiente fórmula: píxeles = dp * densidad Eso parece estar de acuerdo con todos los números informados ((3), (4), (5) arriba) cuando no está en modo de compatibilidad de pantalla: 540x960 = 360x640 * 1.5 Pero en el modo de compatibilidad de pantalla no suma: 540x960! = 360x640 * 1 Entonces, algo está mal.

Creo que la explicación más simple es que los métodos enumerados en (3) anteriores simplemente dan la respuesta incorrecta para "píxeles" cuando están en modo de compatibilidad de pantalla, es decir, estaban destinados a devolver 360x640 "píxeles", pero son incorrectos devolviendo 540x960 en su lugar. Pero puede haber otras formas de verlo.

En cualquier caso, obtener los números deseados independientemente del modo, de las piezas del rompecabezas anteriores, es ciertamente un rompecabezas complicado. He encontrado una forma que parece funcionar en mi teléfono en ambos modos, pero es extremadamente tortuosa y se basa en dos suposiciones que todavía parecen bastante inestables (como se describe en los comentarios del código a continuación).

Aquí está mi receta:

/** 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);
}

¿Hay alguna forma mejor / más limpia de encontrar el tamaño de la pantalla?

Don Hatch
fuente
29
+1 Gran pregunta, y muestra mucho esfuerzo de investigación.
Alex Gittemeier
1
@Don En los documentos , se explica que el modo de compatibilidad dejará de hacer operaciones de "zoom para ajustar" en configuraciones anteriores. Sin embargo, no se explica claramente "cómo funciona", a partir de sus observaciones, creo que simplemente desactivan la escala de densidad, es decir: 1px se convierte en 1dp. Es posible que este cambio se encuentre solo en la parte de representación y DisplayMetricsnunca se actualice de dichos cambios. Hay problemas como este ya archivados.
SD
@ user117: interesante. Bueno, parte de DisplayMetrics se actualizó al menos: la densidad cambió a 1.0. Pero al parecer, anchoPixels / heightPixels no se cambió para que coincida. Con respecto al problema citado, parece que el comportamiento volvió al comportamiento 3.1 (es decir, estoy viendo la altura Los píxeles incluyen la barra de estado ... pero en las unidades incorrectas parece)
Don Hatch
@DonHatch Gracias, amablemente: en realidad estaba tratando de elogiar una pregunta reflexiva que, extrañamente, no es tan bienvenida en StackExchange; tenga en cuenta que la pregunta que es más que "real" no obtiene nada en las respuestas, hablando de la (baja ) calidad del conocimiento de la audiencia sobre el tema. Ahora, puedo estar traumatizado por el hecho de que mis propias preguntas se cierren una tras otra por ser "no reales", y el sentido del humor puede estar fallando, pero comienza a parecer preguntas para las que hay respuestas "agradables". lo que todo esto se hace por aquí ... Y, por supuesto, me upvoted la suya :)
mlvljr
por cierto! Aquí hay algo en la línea de mis sospechas: michael.richter.name/blogs/… (especialmente ver su (1) punto, el de las respuestas elaboradas rápidamente, ¡en realidad el caso con esta Q!). Happy NY, de todos modos (el mío llega en 11 minutos)! :)
mlvljr

Respuestas:

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

Ahora puede medir el tamaño de su pantalla en píxeles, que es una mejor unidad de medida que centímetro porque todos los botones, vistas de texto, etc. se miden en esta unidad. Que lo que uso normalmente

Cobra47
fuente
3
De acuerdo con el Op (punto # 3 específicamente), ¿no sería esto incorrecto en el modo de compatibilidad de pantalla?
Tom
9

Al usar DisplayMetrics, puede obtener el alto y el ancho de la pantalla de cualquier dispositivo. Tenga en cuenta que el ancho y la altura son sensibles a la rotación. Aquí está el código.

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

En tu método onCreate

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

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

Prueba esto.

Preet_Android
fuente
2
no, como dije en (3), métricas. {width, height} Pixels no da la respuesta correcta cuando está en modo de compatibilidad de pantalla.
Don Hatch
También descubrí: Parece lite metrics.heightPixels podría dar el ancho en caso de que la pantalla gire y viceversa.
JohnyTex
8

En su # 6, observa que DecorView parece proporcionar lo que desea, pero no cree que sea real. Creo que es lo más cerca que puedes llegar. De acuerdo con la documentación para Window.getDecorView:

Recupere la vista de decoración de ventana de nivel superior (que contiene el marco / decoraciones de ventana estándar y el contenido del cliente dentro de ella), que se puede agregar como una ventana al administrador de ventanas.

La barra de estado es parte de la decoración de la ventana mencionada allí. Los teclados de software y otras superposiciones recibirán su propia ventana, por lo que no deberían interferir con los valores relevantes. Es correcto que no sea precisamente la métrica de la pantalla, pero si su aplicación está en pantalla completa, siempre debe filtrar el tamaño de pantalla completa a través del traductor de compatibilidad. Otras aplicaciones no tendrán acceso a las de su aplicación Window, por lo que no es necesario preocuparse de que otra aplicación cambie los atributos mientras no está buscando.

Espero que ayude.

Dave
fuente
5

Debería poner esto como un comentario, pero no tengo el representante para eso.
Puede que esta no sea una respuesta totalmente correcta, pero obtuve mis dimensiones cuando cambié la altura y el ancho en el método DisplayMetrics.

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

como dije, esto puede no ser correcto, pero no sé por qué, pero funcionó para mí.

abhyudayasrinet
fuente
Esto se debe a que su pantalla ha girado, creo.
JohnyTex
No fue confiar en mí.
abhyudayasrinet
3

Si está utilizando una API de nivel 17 o superior, consulte getRealMetrics y getRealSize en Display

Para el nivel de API 14, 15 y 16 mira aquí

Exoit
fuente
3

He utilizado el teorema de Pitágoras para encontrar el tamaño diagonal de la pantalla del teléfono / tableta Android, el mismo principio se puede aplicar a la pantalla del iPhone o Blackberry.

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

Pitágoras debe haber sido un genio, conocía la programación de teléfonos inteligentes hace muchos años: p

Naeem A. Malik
fuente
1

Utilizo el siguiente método para obtener el ancho del dispositivo:

public static int getDeviceWidth(Context context){
    WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
    Display display = wm.getDefaultDisplay();
    int width=display.getWidth();
    return width;
}
Ghanshyam Patidar
fuente
Este método está en desuso. Utilice el método de displaymetrics.
Simon
0

Creo que esta función lo ayudará a obtener simplemente el ancho y la altura del tamaño de su pantalla de Android. La función devuelve el ancho y la altura como una matriz de enteros como se muestra a continuación

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;

    }

y en su método de creación, envíe su ancho y alto como se muestra a continuación

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

Descarga el código fuente y pruébalo en tu estudio de Android

Daniel Nyamasyo
fuente
0

Esto funciona para mi:

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

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

Utilicé esto para actualizar el ancho de mis artículos en una vista de reciclador horizontal. (De acuerdo con mis requisitos) ¡Espero que ayude a alguien!

Gagan Deep
fuente
-1

Para esta solución en Kotlin , intente esto:

private fun yourFunction(){
   val metrics = DisplayMetrics()
   windowManager.defaultDisplay.getMetrics(metrics)
   val width = metrics.widthPixels
   val height = metrics.heightPixels
}
Sup.Ia
fuente