comment obtenir la taille de l'écran Android par programme, une fois pour toutes?

132

Comment puis-je connaître la taille de mon écran par programmation, dans les unités utilisées par les événements tactiles et Afficher la mesure / la disposition? En d'autres termes, je veux les coordonnées du coin inférieur droit de l'écran, dans le système de coordonnées utilisé par les événements tactiles getRawX()/getRawY()et View.getLocationOnScreen().

J'hésite à appeler les unités d'événements / vues souhaitées "pixels" car il y a évidemment plusieurs notions de "pixels" sur mon téléphone dans différents modes, et elles ne constituent pas une histoire cohérente.

Je vois que cela a été beaucoup demandé et répondu sur stackoverflow et ailleurs, mais aucune des réponses ne fonctionne réellement sur mon téléphone (droid 4, android 4.1.2) dans tous les modes:

(sensationnel!)

Ceci est pour le code de bibliothèque qui doit fonctionner indépendamment du fait que l'application soit en "mode de compatibilité d'écran" (c'est-à-dire targetSdkVersion <= 10 dans le manifeste) ou non, et je ne veux pas non plus faire d'hypothèses sur la position, la taille , ou l'existence de la barre d'état ou de toute autre décoration d'écran similaire.


Voici les faits:

  1. mon téléphone (un droid 4 sous Android 4.1.2) a 540x960 pixels physiques, c'est-à-dire de petits points lumineux colorés.

  2. la taille de l'écran dans les unités souhaitées, à partir de la visualisation des événements tactiles et de l'affichage des mesures, est de 360x640 lorsque l'application est en mode de compatibilité d'écran, 540x960 lorsque l'application n'est pas en mode de compatibilité d'écran. Ce sont les nombres que j'ai besoin de trouver par programme, sans me faufiler avec des événements tactiles ou des vues pour les trouver, mais j'ai une difficulté extrême à trouver une API qui renverra ces nombres.

  3. Les objets Display et DisplayMetrics obtenus de diverses manières prétendent tous que la taille de l'écran est de 540x960 "pixels" (que ce soit en mode de compatibilité d'écran ou non). Pour être précis, les éléments suivants disent tous 540x960 tout le temps: DisplayMetrics. {Width, height} Pixels, Display.getSize (), Display.getRealSize (), Display.get {Width, Height} (),

  4. Les objets de configuration obtenus de différentes manières disent tous écran {Largeur, Hauteur} Dp = 360x614 (que ce soit en mode compatibilité écran ou non). Je ne pense pas que cela représente tout l'écran, car le rapport hauteur / largeur est incorrect. (Je pense que c'est tout l'écran moins la barre d'état; j'ai besoin de tout l'écran.) Je pense qu'il est prudent de dire que l'écran entier est de 360x640 dp, bien que je ne connaisse aucune API qui renvoie ce 640.

  5. DisplayMetrics obtenus de diverses manières disent que la «densité» est de 1,0f en mode de compatibilité d'écran, de 1,5f en mode de compatibilité d'écran.

  6. L'activité getWindow().getAttributes().{width,height} n'est pas utile car elle contient généralement MATCH_PARENT des tailles plutôt que réelles. Mais je ne peux apparemment obtenir la réponse d'une activité de choix getWindow().getDecorView().getMeasured{Width,Height}() ( ce qui est surprenant en fait depuis decorView de la fenêtre de l'activité n'a pas l' air comme ça prend tout l'écran, on dirait qu'il prend l'écran moins la barre d'état). Mais je ne veux pas me fier à cela parce que si la fenêtre est redimensionnée (un clavier logiciel apparaît? Quelqu'un appelle window.setAttributes ()? Ou peut-être que je ne suis pas du tout dans une activité), cela va clairement être tout faux.

Je comprends que la formule suivante est censée tenir: pixels = dp * densité Cela semble être en accord avec tous les nombres rapportés ((3), (4), (5) ci-dessus) lorsque vous n'êtes pas en mode de compatibilité d'écran: 540x960 = 360x640 * 1.5 Mais en mode de compatibilité d'écran, cela ne correspond pas: 540x960! = 360x640 * 1 Donc, quelque chose ne va pas.

L'explication la plus simple, je pense, est que les méthodes énumérées dans (3) ci-dessus donnent simplement la mauvaise réponse pour "pixels" en mode de compatibilité d'écran - c'est-à-dire qu'elles étaient destinées à renvoyer 360x640 "pixels" mais elles sont à tort renvoyant 540x960 à la place. Mais il peut y avoir d'autres façons de voir les choses.

Dans tous les cas, obtenir les nombres souhaités quel que soit le mode, à partir des pièces de puzzle ci-dessus, est certainement un casse-tête délicat. J'ai trouvé un moyen qui semble fonctionner sur mon téléphone dans les deux modes, mais il est extrêmement détourné et repose sur deux hypothèses qui semblent encore assez incertaines (comme décrit dans les commentaires de code ci-dessous).

Voici ma recette:

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

Existe-t-il un moyen meilleur / plus propre de trouver la taille de l'écran?

Don Hatch
la source
29
+1 Excellente question et montre beaucoup d'efforts de recherche.
Alex Gittemeier
1
@Don Dans la documentation , il est expliqué que le mode de compatibilité cessera d'effectuer l'opération "zoomer pour s'adapter" sur les anciennes configurations. Cependant, il n'est pas clairement expliqué "comment cela fonctionne", d'après vos observations, je pense qu'ils désactivent simplement la mise à l'échelle de la densité, c'est-à-dire: 1px devient 1dp. Il se peut que cette modification ne concerne que la partie de rendu et DisplayMetricsne soit jamais mise à jour de ces modifications. Il y a déjà des problèmes comme celui-ci .
SD
@ user117 - intéressant. Une partie de DisplayMetrics a au moins été mise à jour - la densité est passée à 1.0. Mais widthPixels / heightPixels n'a pas été modifié pour correspondre, semble-t-il. En ce qui concerne le problème cité, il semble que le comportement soit revenu au comportement 3.1 (c'est-à-dire que je vois que les pixels de hauteur incluent la barre d'état ... mais dans les mauvaises unités, il semble)
Don Hatch
@DonHatch Merci, gentiment - j'essayais en fait de faire l'éloge d'une question réfléchie d'une sorte étrangement pas si bienvenue sur StackExchange - notez comment la question étant plus que "réelle" n'obtient rien dans les réponses, en parlant du (faible ) qualité des connaissances du public sur le sujet. Maintenant, je suis peut-être traumatisé par le fait que mes propres questions sont fermées les unes après les autres parce qu’elles ne sont «pas vraies», et le sens de l’humour me fait peut-être défaut, mais cela commence à ressembler à des questions pour lesquelles il y a des réponses «gentilles». ce que tout cela devient ici ... Et bien sûr, j'ai voté pour le vôtre :)
mlvljr
btw! voici quelque chose dans le sens de mes soupçons: michael.richter.name/blogs/… (en particulier voir son (1) point, celui sur les réponses rapidement élaborées - en fait exactement le cas avec ce Q!). Bon NY, en tout cas (le mien arrive dans 11 minutes)! :)
mlvljr

Réponses:

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

Vous pouvez maintenant mesurer la taille de votre écran en pixel qui est une meilleure unité de mesure que le centimètre car tous les boutons, vues de texte, etc. sont mesurés dans cette unité. C'est ce que j'utilise normalement

Cobra47
la source
3
Selon l'Op (point n ° 3 en particulier), cela ne serait-il pas incorrect en mode de compatibilité d'écran?
Tom
9

En utilisant DisplayMetrics, vous pouvez obtenir la hauteur et la largeur de l'écran de n'importe quel appareil. Notez que la largeur et la hauteur sont sensibles à la rotation. voici le code.

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

Dans votre méthode onCreate

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

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

Essaye ça.

Preet_Android
la source
2
non, comme je l'ai dit dans (3), metrics. {width, height} Pixels ne donne pas la bonne réponse en mode de compatibilité d'écran.
Don Hatch
J'ai aussi découvert: il semble que des métriques légères.heightPixels pourrait donner la largeur au cas où l'écran serait tourné et vice versa!
JohnyTex
8

Dans votre n ° 6, vous notez que DecorView semble fournir ce que vous voulez, mais vous ne pensez pas qu'il est réalisable. Je crois que c'est aussi proche que possible. Selon la documentation pour Window.getDecorView:

Récupérez la vue de décoration de fenêtre de niveau supérieur (contenant le cadre / les décorations de fenêtre standard et le contenu du client à l'intérieur), qui peut être ajoutée en tant que fenêtre au gestionnaire de fenêtres.

La barre d'état fait partie de la décoration de fenêtre mentionnée ici. Les claviers logiciels et autres superpositions recevront leur propre fenêtre, ils ne devraient donc pas interférer avec les valeurs pertinentes. Il est correct que ce ne soit pas précisément les métriques d'affichage, mais si votre application est en plein écran, elle doit toujours être la taille plein écran filtrée via le traducteur de compatibilité. Les autres applications n'auront pas accès à celles de votre application Window, vous n'avez donc pas à vous soucier de la modification des attributs par une autre application pendant que vous ne cherchez pas.

J'espère que cela pourra aider.

Dave
la source
5

Je devrais mettre ceci en commentaire mais je n'ai pas le représentant pour cela.
Ce n'est peut-être pas une réponse totalement correcte, mais j'ai obtenu mes dimensions lorsque j'ai changé la hauteur et la largeur dans la méthode DisplayMetrics.

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

comme je l'ai dit, cela peut ne pas être correct mais je ne sais pas pourquoi mais cela a fonctionné pour moi.

abhyudayasrinet
la source
C'est parce que votre écran a tourné, je crois.
JohnyTex
Ce n'était pas me faire confiance.
abhyudayasrinet
3

Si vous utilisez l'API de niveau 17 ou supérieur, consultez getRealMetrics et getRealSize dans Display

Pour les niveaux d'API 14, 15 et 16, regardez ici

Exoît
la source
3

J'ai utilisé le théorème de Pythagore pour trouver la taille diagonale de l'écran du téléphone / tablette Android, le même principe peut être appliqué à l'écran de l'iPhone ou du 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

Pythagore devait être un génie, il connaissait la programmation des téléphones intelligents il y a tant d'années: p

Naeem A. Malik
la source
1

J'utilise la méthode ci-dessous pour obtenir la largeur de l'appareil:

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
la source
Cette méthode est obsolète. Veuillez utiliser la méthode displaymetrics.
Simon
0

Je pense que cette fonction vous aidera à obtenir simplement la largeur et la hauteur de la taille de votre écran Android. La fonction renvoie la largeur et la hauteur sous forme de tableau d'entiers comme indiqué ci-dessous

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;

    }

et sur votre méthode de création, affichez votre largeur et votre hauteur comme indiqué ci-dessous

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

Téléchargez le code source et testez-le sur votre studio Android

Daniel Nyamasyo
la source
0

Cela fonctionne pour moi:

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

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

Je l'ai utilisé pour mettre à jour la largeur de mes articles dans une vue horizontale du recycleur (selon mes besoins) J'espère que cela aide quelqu'un!

Gagan Deep
la source
-1

Pour cette solution à Kotlin , essayez ceci:

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