134 votes

comment obtenir la taille de l'écran d'Android de manière programmatique, une fois pour toutes ?

Comment puis-je connaître la taille de mon écran de manière programmatique, dans les unités utilisées par les événements tactiles et la mesure/la disposition de l'écran ? 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énement/de vue souhaitées des "pixels". car il y a manifestement plusieurs notions de "pixels". sur mon téléphone dans différents modes, et elles ne s'ajoutent pas à une histoire cohérente.

Je vois que cette question a été beaucoup posée et répondue sur stackoverflow et ailleurs, mais aucun des réponses fonctionnent réellement sur mon téléphone (droid 4, Android 4.1.2) dans tous les modes :

(wow !)

C'est pour le code de la bibliothèque qui doit fonctionner indépendamment du fait que l'application soit en "mode de compatibilité écran" (i.e. targetSdkVersion<=10 dans le manifeste) ou non. (c'est-à-dire targetSdkVersion<=10 dans le manifeste) ou non, et je ne veux pas non plus faire d'hypothèses de la position, de la taille ou de 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 fonctionnant sous Android 4.1.2) a 540x960 pixels physiques, c'est à dire des petits points colorés et lumineux.

  2. la taille de l'écran dans les unités souhaitées, d'après les événements tactiles et les mesures d'affichage, 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 chiffres que je dois trouver par programmation, sans avoir à manipuler les événements tactiles ou Views pour les trouver, mais j'ai beaucoup de mal à trouver une API qui renvoie ces chiffres.

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

  4. Objets de configuration obtenus de diverses manières tous disent screen{Width,Height}Dp = 360x614 (que ce soit en mode de compatibilité d'écran ou non). Je ne pense pas que cela représente la totalité de l'écran, puisque le ratio d'aspect est faux. (Je pense que c'est l'écran entier moins la barre d'état ; j'ai besoin de l'écran entier). Je pense qu'il est sûr de dire que l'écran entier est 360x640 dp, bien que je ne connaisse pas d'API qui renvoie ces 640.

  5. DisplayMetrics obtenu de diverses manières disons que la "densité" est 1.0f en mode Screen Compat, 1.5f quand l'écran n'est pas en mode compatible.

  6. L'activité getWindow().getAttributes().{width,height} n'est pas utile car il contient généralement MATCH_PARENT plutôt que les tailles réelles. Mais je peux apparemment obtenir la réponse souhaitée à partir de l'activité getWindow().getDecorView().getMeasured{Width,Height}() (ce qui est en fait surprenant puisque la decorView de la fenêtre de l'activité de la fenêtre de l'activité ne regardez comme si elle prenait tout l'écran ; il semble qu'il occupe l'écran moins la barre d'état). Mais je ne veux pas me fier à cela, car si la fenêtre est redimensionnée (apparition d'un clavier souple ? (apparition d'un clavier souple ? quelqu'un appelle window.setAttributes() ? ou peut-être que je ne suis pas du tout dans une activité), il est clair que tout sera faux.

Je comprends que la formule suivante est censée tenir : pixels = dp * densité Cela semble correspondre à tous les chiffres rapportés ((3),(4),(5) ci-dessus). lorsque pas en mode de compatibilité d'écran : 540x960 = 360x640 * 1,5 Mais en mode de compatibilité d'écran, ça ne colle pas : 540x960 != 360x640 * 1 Donc, il y a un problème.

L'explication la plus simple, je pense, est que les méthodes listées dans (3) ci-dessus donnent simplement une mauvaise réponse pour les "pixels" lorsque en mode "screen compat", c'est-à-dire qu'elles étaient censées de renvoyer des "pixels" de 360x640, mais elles renvoient à tort 540x960. Mais il y a peut-être d'autres façons de voir les choses.

Dans tous les cas, obtenir les chiffres souhaités, quel que soit le mode, à partir des pièces du 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 c'est extrêmement compliqué, et il repose sur deux hypothèses qui semblent encore assez incertaines (comme décrit dans les commentaires du 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 plus efficace et plus propre pour trouver la taille de l'écran ?

32 votes

+1 Excellente question, qui témoigne d'un grand effort de recherche.

1 votes

@Don In docs Il est expliqué que le mode de compatibilité empêchera l'opération "zoom to fit" 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 que 1px devient 1dp. Il se peut que ce changement ne concerne que la partie rendu, et que l'on ne puisse pas l'appliquer à l'image. DisplayMetrics n'est jamais informé de ces changements. Il y a des problèmes comme ce déjà déposé.

0 votes

@user117 - intéressant. Bien partie de DisplayMetrics a été mis à jour au moins - la densité est passée à 1.0. Mais widthPixels/heightPixels n'a pas été modifié pour correspondre, il semble. En ce qui concerne le problème cité, il semble que le comportement soit revenu à celui de la version 3.1 (c'est-à-dire que je vois heightPixels inclure la barre d'état... mais dans les mauvaises unités il semble)

41voto

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

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

3 votes

Selon l'Op (point #3 spécifiquement), cela ne serait-il pas incorrect en mode compat d'écran ?

9voto

Preet_Android Points 1

En utilisant les 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

Essayez ça.

4 votes

Non, comme je l'ai dit dans (3), metrics.{width,height}Pixels est pas donner la bonne réponse en mode de compatibilité d'écran.

0 votes

J'ai aussi découvert : Il semble que lite metrics.heightPixels puisse donner la largeur en cas de rotation de l'écran et vice versa !

8voto

Dave Points 2391

Dans votre numéro 6, vous notez que le DecorView semble fournir ce que vous voulez, mais vous ne pensez pas qu'il soit réalisable. Je crois que vous ne pouvez pas faire mieux. Selon la documentation de Window.getDecorView :

Récupère la vue décorative de la fenêtre de haut niveau (contenant le cadre/décorations standard de la fenêtre et le contenu du client à l'intérieur), qui peut être ajoutée comme fenêtre au gestionnaire de fenêtres.

La barre d'état fait partie de la décoration de la 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 vrai que ce n'est pas précisément la métrique d'affichage, mais si votre application est en plein écran, elle devrait toujours avoir la taille du plein écran filtrée par le traducteur de compatibilité. Les autres applications n'auront pas accès à la fenêtre de votre application. Window Il n'y a donc pas lieu de s'inquiéter qu'une autre application modifie les attributs pendant que vous ne regardez pas.

J'espère que cela vous aidera.

3voto

Exoit Points 56

Si vous utilisez le niveau d'api 17 ou plus, consultez getRealMetrics et getRealSize dans la section Afficher

Pour les niveaux 14, 15 et 16 de l'API, regardez. ici

3voto

Naeem A. Malik Points 198

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X