web-dev-qa-db-fra.com

Mesurer la hauteur du texte à dessiner sur Canvas (Android)

Un moyen simple de mesurer la hauteur du texte? Je le fais maintenant en utilisant measureText() de Paint pour obtenir la largeur, puis en essayant et en recherchant une valeur pour obtenir une hauteur approximative. J'ai aussi joué avec FontMetrics, mais toutes ces méthodes semblent approximatives.

J'essaie de faire évoluer les choses pour différentes résolutions. Je peux le faire, mais je me retrouve avec un code incroyablement détaillé avec beaucoup de calculs pour déterminer les tailles relatives. Je déteste ça! Il doit y avoir une meilleure façon.

112
Danedo

Qu'en est-il de Paint.getTextBounds () (méthode de l'objet)

126
bramp

Il existe différentes façons de mesurer la hauteur en fonction de vos besoins.

getTextBounds

Si vous faites quelque chose comme centrer précisément une petite quantité de texte fixe, vous voudrez probablement getTextBounds. Vous pouvez obtenir le rectangle englobant comme ceci

Rect bounds = new Rect();
mTextPaint.getTextBounds(mText, 0, mText.length(), bounds);
int height = bounds.height();

Comme vous pouvez le constater pour les images suivantes, différentes chaînes donnent des hauteurs différentes (indiquées en rouge).

enter image description here

Ces hauteurs différentes pourraient être un inconvénient dans certaines situations où vous avez simplement besoin d'une hauteur constante, quel que soit le texte. Voir la section suivante.

Paint.FontMetrics

Vous pouvez calculer la taille de la police à partir des métriques de police. La hauteur est toujours la même car elle est obtenue à partir de la police, pas de chaîne de texte particulière.

Paint.FontMetrics fm = mTextPaint.getFontMetrics();
float height = fm.descent - fm.ascent;

La ligne de base est la ligne sur laquelle repose le texte. La descente est généralement la plus éloignée qu'un personnage passe au-dessous de la ligne et la montée est généralement la plus éloignée qu'un personnage passe au-dessus de la ligne. Pour obtenir la hauteur, vous devez soustraire l'ascension car il s'agit d'une valeur négative. (La ligne de base est y=0 et y diminue l’écran.)

Regardez l'image suivante. Les hauteurs des deux cordes sont 234.375.

enter image description here

Si vous voulez la hauteur de ligne plutôt que seulement la hauteur de texte, vous pouvez procéder comme suit:

float height = fm.bottom - fm.top + fm.leading; // 265.4297

Ce sont les bottom et top de la ligne. Le premier (espacement interligne) est généralement égal à zéro, mais vous devez quand même l'ajouter.

Les images ci-dessus proviennent de ce projet . Vous pouvez y jouer pour voir comment fonctionnent les métriques de polices.

StaticLayout

Pour mesurer la hauteur d'un texte multiligne, utilisez un StaticLayout. J'en ai parlé de manière assez détaillée dans cette réponse , mais la méthode de base pour obtenir cette hauteur est la suivante:

String text = "This is some text. This is some text. This is some text. This is some text. This is some text. This is some text.";

TextPaint myTextPaint = new TextPaint();
myTextPaint.setAntiAlias(true);
myTextPaint.setTextSize(16 * getResources().getDisplayMetrics().density);
myTextPaint.setColor(0xFF000000);

int width = 200;
Layout.Alignment alignment = Layout.Alignment.ALIGN_NORMAL;
float spacingMultiplier = 1;
float spacingAddition = 0;
boolean includePadding = false;

StaticLayout myStaticLayout = new StaticLayout(text, myTextPaint, width, alignment, spacingMultiplier, spacingAddition, includePadding);

float height = myStaticLayout.getHeight(); 
151
Suragch

La réponse de @ bramp est correcte - partiellement, en ce sens qu'elle ne mentionne pas que les limites calculées seront le rectangle minimal contenant le texte intégralement avec des coordonnées de départ implicites égales à 0, 0.

Cela signifie que la hauteur de, par exemple, "Py" sera différente de la hauteur de "py", "hi", "oi" ou "aw", car ils requièrent des hauteurs différentes au niveau des pixels.

Cela n’est en aucun cas un équivalent de FontMetrics en Java classique.

Bien que la largeur d'un texte ne soit pas très pénible, la hauteur l'est.

En particulier, si vous devez centrer verticalement le texte dessiné, essayez d’obtenir les limites du texte "a" (sans guillemets) au lieu d’utiliser le texte que vous souhaitez dessiner. Travaille pour moi...

Voici ce que je veux dire:

Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.LINEAR_TEXT_FLAG);

Paint.setStyle(Paint.Style.FILL);
Paint.setColor(color);
Paint.setTextAlign(Paint.Align.CENTER);
Paint.setTextSize(textSize);

Rect bounds = new Rect();
Paint.getTextBounds("a", 0, 1, bounds);

buffer.drawText(this.myText, canvasWidth >> 1, (canvasHeight + bounds.height()) >> 1, Paint);
// remember x >> 1 is equivalent to x / 2, but works much much faster

Centrer verticalement le texte signifie aligner verticalement le rectangle de délimitation - ce qui est différent pour différents textes (majuscules, longues lettres, etc.). Mais ce que nous voulons réellement faire est d’aligner également les lignes de base des textes rendus, de sorte qu’elles ne paraissent ni élevées ni rainurées. Ainsi, tant que nous connaissons le centre de la plus petite lettre ("a" par exemple), nous pouvons alors réutiliser son alignement pour le reste des textes. Cela alignera tous les textes ainsi que les aligner.

82
Nar Gar

La hauteur correspond à la taille du texte que vous avez définie dans la variable Paint.

Une autre façon de connaître la hauteur est

mPaint.getTextSize();
15
kimnod

Vous pouvez utiliser la classe Android.text.StaticLayout Pour spécifier les limites requises, puis appeler getHeight(). Vous pouvez dessiner le texte (contenu dans la mise en page) en appelant sa méthode draw(Canvas).

3
intrepidis

Vous pouvez simplement obtenir la taille du texte d'un objet Paint à l'aide de la méthode getTextSize (). Par exemple:

Paint mTextPaint = new Paint (Paint.ANTI_ALIAS_FLAG);
//use densityMultiplier to take into account different pixel densities
final float densityMultiplier = getContext().getResources()
            .getDisplayMetrics().density;  
mTextPaint.setTextSize(24.0f*densityMultiplier);

//...

float size = mTextPaint.getTextSize();
2
moondroid

Vous devez utiliser Rect.width() et Rect.Height(), qui sont revenus de getTextBounds() à la place. Ça marche pour moi.

1
Putti