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 :
- Puis-je déterminer la largeur de l'écran de manière programmatique dans une application Android ?
- Comment obtenir la taille de l'écran de manière programmatique dans Android ?
- Android définit la visibilité de la vue de manière programmatique en fonction de la taille de l'écran
- Comment obtenir la hauteur de l'écran dans Android ?
- Obtenir la hauteur de l'écran dans Android
- https://groups.google.com/forum/#!topic/Android-developers/IpxnfvDFrpc
- http://shuklaxyz.blogspot.com/2012/02/how-to-programmatically-figure-out.html
- http://coderock.net/how-to-determine-screen-resolution-programmatically/
- http://www.codeproject.com/Tips/313848/Get-actual-screen-size-for-the-application-layout
- Android et réglage programmatique de la largeur et de la hauteur en unités dp
- http://www.simplecodestuffs.com/how-to-get-screen-dimensions-programmatically-in-Android/
- http://www.androidsnippets.com/get-size-and-orientation-of-the-screen
- http://grokbase.com/t/gg/Android-developers/127aatfqb6/how-to-determine-screen-resolution-programmatically
(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 :
-
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.
-
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.
-
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}(),
-
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.
-
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.
-
L'activité
getWindow().getAttributes().{width,height}
n'est pas utile car il contient généralementMATCH_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)
0 votes
@DonHatch Merci, gentiment -- J'essayais en fait de faire l'éloge d'une sorte de question réfléchie qui n'est étrangement pas la bienvenue sur StackExchange -- notez comment la question étant plus que "réelle" n'obtient rien dans les réponses, parlant de la (faible) qualité des connaissances du public sur le sujet. Maintenant, je suis peut-être traumatisé par mes propres questions qui ont été fermées l'une après l'autre parce qu'elles n'étaient pas "réelles", et le sens de l'humour peut me faire défaut, mais il commence à sembler que les questions pour lesquelles il y a des réponses "gentilles" et réciproques sont vraiment ce dont il s'agit ici... Et bien sûr, j'ai voté pour la vôtre :)
0 votes
Btw ! voici quelque chose qui va dans le sens de mes soupçons : michael.richter.name/blogs/ (en particulier, voir son point (1), celui sur les réponses rapidement rédigées - en fait, c'est exactement le cas pour cette question). Joyeux Noël, en tout cas (le mien arrive dans 11 minutes) ! :)
0 votes
Méfiez-vous des solutions "une fois pour toutes" : youtube.com/watch?v=0SYpUSjSgFg