web-dev-qa-db-fra.com

getDimension () / getDimensionPixelSize () - problème de multiplicateur

J'ai donc Android 2.3.5 appareil qui est NORMAL/HDPI. J'ai un dimens.xml dans mon projet:

...
    <dimen name="gameresult_congrats_label_msg_textSize">20sp</dimen>
...

ce fichier est absolument identique dans les dossiers values-normal/values-hdpi et ainsi de suite. Dans ma première application d'activité, je montre cette valeur en utilisant:

Toast.makeText(this, "textSize is "+getResources().getDimensionPixelSize(R.dimen.gameresult_congrats_label_msg_textSize), Toast.LENGTH_SHORT).show();

et il affiche 30. J'ai également essayé:

Toast.makeText(this, "textSize is "+getResources().getDimension(R.dimen.gameresult_congrats_label_msg_textSize), Toast.LENGTH_SHORT).show();

mais le résultat est le même. Mais seulement quand j'ai essayé ceci:

Toast.makeText(this, "textSize is "+getResources().getString(R.dimen.gameresult_congrats_label_msg_textSize), Toast.LENGTH_SHORT).show();

J'ai enfin mon "20sp"! Mais pourquoi ça? Les documents officiels disent que ces méthodes renvoie

Valeur de dimension de ressource multipliée par la mesure appropriée.

J'ai vérifié cela en modifiant ma valeur à 25 et j'ai obtenu 38, ce qui signifie que aos utilise un multiplicateur de 1,5. Mais pourquoi? Il obtient déjà de la valeur à partir du dossier approprié, ce qui signifie qu'il obtient une valeur prête à l'emploi! D'où aos obtient ce multiplicateur 1,5x? Je sais que cela dépend de DisplayMetrics. Mais comment il calcule 1,5x?
[~ # ~] mise à jour [~ # ~]
Je comprends le multiplicateur mais, voyez-vous, le vrai problème ici concerne la double mise à l'échelle. Et c'est pourquoi j'ai posé cette question.
Donc, si j'ai du layout.xml (dans le dossier res\layout) avec TexView défini comme:

<TextView
    Android:id="@+id/congratsLabel"
    ...
    Android:textSize="@dimen/gameresult_congrats_label_msg_textSize" />

Tout semble correct. Je veux dire que textview est comme je m'y attendais.
Maintenant, faisons de même dans le code:

TextView congratsLabel = fineViewById(R.id.congratsLabel); 
textSize = getResources().getDimension(R.dimen.gameresult_congrats_label_msg_textSize)
congratsLabel.setTextSize(textSize) 

et voici le problème !!! getResources (). getDimension () renvoie une valeur [~ # ~] mise à l'échelle [~ # ~] et c'est ok. Mais la taille résultante de mon textView sera 1,5 plus grande que ce à quoi je m'attendais parce que setTextSize fonctionne avec SP et voici la deuxième échelle! Et c'est pourquoi AOS fait que la taille du texte résultant est réduite à 45 (initialement définie comme 20sp).

14
Stan

Selon la formation prenant en charge différentes densités d'écran , hdpi est de taille normale 1,5x (mdpi). Comme getDimensionPixelSize prend en compte cette différence lors de la conversion en pixels, la valeur renvoyée sera 1,5 fois votre valeur dans sp.

Notez que sp dépend également de la taille de texte préférée de l'utilisateur et peut donc changer pour être encore plus grand que 1,5 fois votre valeur attendue.

14
ianhanniballake

Juste pour clarifier (informations obtenues en inspectant Android):

Resources.getDimension() et getDimensionPixelOffset()/getDimensionPixelSize() ne diffèrent que par le fait que le premier renvoie float tandis que les deux derniers renvoient la même valeur arrondie à int convenablement. Pour chacun d'eux, la valeur de retour est en pixels bruts.

Les trois fonctions sont implémentées en appelant Resources.getValue() et en convertissant le TypedValue ainsi obtenu en appelant TypedValue.complexToDimension(), TypedValue.complexToDimensionPixelOffset() et TypedValue.complexToDimensionPixelSize() , respectivement.

Par conséquent, si vous souhaitez obtenir la valeur "brute" avec l'unité spécifiée dans la source XML, appelez Resources.getValue() et utilisez les méthodes de la classe TypedValue.

24
Jaromír Adamec

La méthode getDimension () convertit les valeurs dp ou sp en pixels en fonction de la densité d'écran actuelle. Ceci est très utile car vous n'avez pas à le faire vous-même, lorsque vous souhaitez définir la largeur ou la taille du texte Java Java (ils n'acceptent que les pixels).

Mais si vous avez besoin de sp ou dp d'origine, vous pouvez faire du "reverse engineering".

Étape 1. Vérifier le rapport d'échelle actuel (basé sur la densité de l'écran):

float scaleRatio = getResources().getDisplayMetrics().density;

Étape 2. Obtenez la dimension de dimens.xml

float dimenPix = getResources().getDimension(R.dimen.your_dimen_name);

Étape 3. Faites quelques calculs

float dimenOrginal = dimenPix/scaleRatio;

Remarques:

  • généralement, vous avez besoin d'int pour les méthodes de dimension (comme setWidth ()), vous devez donc convertir le résultat flottant en int par exemple en utilisant Math.round ()
  • résultat plus précis lors de l'arrondi à l'int, vous pouvez obtenir une telle formule (dimenPix-0.5f)/scaleRatio
  • en cas de sp, vous pouvez également prendre en compte les préférences des utilisateurs concernant l'échelle de texte

En savoir plus sur les dimensions dans Android: http://Android4beginners.com/2013/07/appendix-c-everything-about-sizes-and-dimensions-in-Android/

15
Android4Beginners

Si quelqu'un d'autre en a besoin:

Pour résoudre le problème de double mise à l'échelle Stan affiche lors de l'utilisation de getDimensionPixelSize avec TextView.setTextSize:

Vous pouvez utiliser la version alternative de setTextSize où vous pouvez spécifier l'unité comme ceci:

title.setTextSize(TypedValue.COMPLEX_UNIT_PX, getResources().getDimensionPixelSize(R.dimen.title));
6
Antoine

Parce que ... NORMAL n'est PAS hdpi ...
Normal est mdpi (160dpi) = 1,0x.
hdpi (240 dpi) est 1,5x.
xhdpi (320dpi) est 2,0x.
xxdpi (480dpi) est 3.0x.
xxxhdpi (640dpi) est 4,0x.
Et (dernier point, mais non des moindres), ldpi (120 dpi) est de 0,75x.

1
Phantômaxx