Cible: Android> = 1,6 sur un canevas pur.
Supposons que je veuille écrire une fonction qui dessine un grand rectangle rouge (largeur, hauteur), puis un texte noir Hello World à l'intérieur. Je veux que le texte soit visuellement au centre du rectangle. Alors essayons:
void drawHelloRectangle(Canvas c, int topLeftX,
int topLeftY, int width, int height) {
Paint mPaint = new Paint();
// height of 'Hello World'; height*0.7 looks good
int fontHeight = (int)(height*0.7);
mPaint.setColor(COLOR_RED);
mPaint.setStyle(Style.FILL);
c.drawRect( topLeftX, topLeftY, topLeftX+width, topLeftY+height, mPaint);
mPaint.setTextSize(fontHeight);
mPaint.setColor(COLOR_BLACK);
mPaint.setTextAlign(Align.CENTER);
c.drawText( "Hello World", topLeftX+width/2, ????, mPaint);
}
Maintenant, je ne sais pas quoi mettre dans l'argument de drawText marqué par ????
, c'est-à-dire que je ne sais pas comment aligner verticalement le texte.
Quelque chose comme
???? = topLeftY + height/2 + fontHeight/2 - fontHeight/8;
semble fonctionner plus ou moins bien, mais il doit y avoir un meilleur moyen.
cx
et cy
:private final Rect textBounds = new Rect(); //don't new this up in a draw method
public void drawTextCentred(Canvas canvas, Paint paint, String text, float cx, float cy){
Paint.getTextBounds(text, 0, text.length(), textBounds);
canvas.drawText(text, cx - textBounds.exactCenterX(), cy - textBounds.exactCenterY(), Paint);
}
height()/2f
ne fonctionne-t-il pas de la même manière?exactCentre()
= (top + bottom) / 2f
.
height()/2f
= (bottom - top) / 2f
Cela ne donnerait le même résultat que lorsque top
est 0
. Cela peut être le cas pour certaines polices de toutes tailles ou d'autres polices de certaines tailles, mais pas pour toutes les polices de toutes tailles.
textY = topLeftY + height/2 - (mPaint.descent() + mPaint.ascent()) / 2
La distance entre "base" et "centre" devrait être -(mPaint.descent() + mPaint.ascent()) / 2
Basé sur la réponse de steelbytes, le code mis à jour ressemblerait à ceci:
void drawHelloRectangle(Canvas c, int topLeftX, int topLeftY, int width, int height) {
Paint mPaint = new Paint();
// height of 'Hello World'; height*0.7 looks good
int fontHeight = (int)(height*0.7);
mPaint.setColor(COLOR_RED);
mPaint.setStyle(Style.FILL);
c.drawRect( topLeftX, topLeftY, topLeftX+width, topLeftY+height, mPaint);
mPaint.setTextSize(fontHeight);
mPaint.setColor(COLOR_BLACK);
mPaint.setTextAlign(Align.CENTER);
String textToDraw = new String("Hello World");
Rect bounds = new Rect();
mPaint.getTextBounds(textToDraw, 0, textToDraw.length(), bounds);
c.drawText(textToDraw, topLeftX+width/2, topLeftY+height/2+(bounds.bottom-bounds.top)/2, mPaint);
}
Comme dessiner du texte en Y signifie que la ligne de base du texte se terminera par une différence de Y pixels par rapport à l'Origine, voici ce que vous devez faire pour centrer du texte dans un rectangle de (width, height)
dimensions:
Paint.setTextAlign(Paint.Align.CENTER); // centers horizontally
canvas.drawText(text, width / 2, (height - Paint.ascent()) / 2, Paint);
Gardez à l'esprit que l'ascension est négative (ce qui explique le signe moins).
Cela ne prend pas en compte la descente, ce qui correspond généralement à ce que vous souhaitez (la remontée correspond généralement à la hauteur des majuscules au-dessus de la ligne de base).
en utilisant mPaint.getTextBounds (), vous pouvez demander quelle sera la taille du texte une fois dessiné, puis en utilisant cette information, vous pourrez calculer où vous voulez le dessiner.
public static PointF getTextCenterToDraw(String text, RectF region, Paint paint) {
Rect textBounds = new Rect();
Paint.getTextBounds(text, 0, text.length(), textBounds);
float x = region.centerX() - textBounds.width() * 0.4f;
float y = region.centerY() + textBounds.height() * 0.4f;
return new PointF(x, y);
}
Usage:
PointF p = getTextCenterToDraw(text, rect, Paint);
canvas.drawText(text, p.x, p.y, Paint);
Je suis tombé sur cette question en essayant de résoudre mon problème, et la réponse de @ Weston me convient parfaitement.
Dans le cas de Kotlin:
private fun drawText(canvas: Canvas) {
Paint.textSize = 80f
val text = "Hello!"
val textBounds = Rect()
Paint.getTextBounds(text, 0, text.length, textBounds);
canvas.drawText(text, cx- textBounds.exactCenterX(), cy - textBounds.exactCenterY(), Paint);
//in case of another Rect as a container:
//canvas.drawText(text, containerRect.exactCenterX()- textBounds.exactCenterX(), containerRect.exactCenterY() - textBounds.exactCenterY(), Paint);
}
Voici une méthode d’extension SkiaSharp C # pour ceux qui le cherchent
public static void DrawTextCenteredVertically(this SKCanvas canvas, string text, SKPaint Paint, SKPoint point)
{
var textY = point.Y + (((-Paint.FontMetrics.Ascent + Paint.FontMetrics.Descent) / 2) - Paint.FontMetrics.Descent);
canvas.DrawText(text, point.X, textY, Paint);
}