Testo Android Center su tela


191

Sto cercando di visualizzare un testo utilizzando il codice seguente. Il problema è che il testo non è centrato in senso orizzontale. Quando imposto le coordinate per drawText, imposta la parte inferiore del testo in questa posizione. Vorrei che il testo fosse disegnato in modo che il testo fosse centrato anche in senso orizzontale.

Questa è una foto per mostrare ulteriormente il mio problema:

Immagine dello schermo

@Override
protected void onDraw(Canvas canvas) {
    // TODO Auto-generated method stub
    super.onDraw(canvas);
    //canvas.drawRGB(2, 2, 200);
    Paint textPaint = new Paint();
    textPaint.setARGB(200, 254, 0, 0);
    textPaint.setTextAlign(Align.CENTER);
    textPaint.setTypeface(font);
    textPaint.setTextSize(300);
    canvas.drawText("Hello", canvas.getWidth()/2, canvas.getHeight()/2  , textPaint);
}

20
Non dichiarerei il tuo oggetto paint all'interno del tuo evento onDraw. Viene ricreato ogni volta che viene ridisegnato. Valuta di renderla una variabile di classe privata.
Christopher Rathgeb,

8
Compagno! Ricorda che il tuo link immagine è NSFW! Non intendo essere prudente, ma non ho bisogno di pubblicità con donne in topless che appaiono sul mio schermo in ufficio.
Michael Scheper,

5
@MichaelScheper Siamo spiacenti, ho aggiornato il link!
Sebastian,

23
@Sebastian Hey hai ancora quel link?
S.Lukas,

@ S.Lukas hhahaha
BOTJr.

Risposte:


378

Prova quanto segue:

 int xPos = (canvas.getWidth() / 2);
 int yPos = (int) ((canvas.getHeight() / 2) - ((textPaint.descent() + textPaint.ascent()) / 2)) ; 
 //((textPaint.descent() + textPaint.ascent()) / 2) is the distance from the baseline to the center.

 canvas.drawText("Hello", xPos, yPos, textPaint);

10
Bella risposta. Per me ho usato quanto segue in quanto avevo bisogno di centrare il testo orizzontalmente completamente anziché il testo per iniziare dalla posizione centrale: int xPos = (Width - textPaint.TextSize * Math.Abs ​​(_text.Length / 2)) / 2; Non sono sicuro se esiste un modo migliore per ottenere questo risultato.
paj7777,

E probabilmente è meglio lanciare _text.Length su un float perché ovviamente non funzionerà con lunghezze di testo dispari.
paj7777,

61
paj7777, non è necessario se si imposta textPaint.setTextAlign (Align.CENTER);
Costi Muraru,

@ paj7777 Ciò avrebbe funzionato comunque solo per i caratteri a larghezza fissa. Inoltre, non è necessario lanciare un float; se dividi per un float, il risultato sarà un float. ad es. float halfLength = text.length() / 2f;Questo si chiama promozione del tipo .
Michael Scheper,

2
Ho confrontato questo approccio (= centra con Paint.descent()e Paint.ascent()) con l'approccio per centrare il testo con Paint.getTextBounds()nella mia risposta di seguito. Paint.descent()e Paint.ascent()non prendere in considerazione il testo effettivo. (Puoi riconoscere questa inesattezza nello screenshot nel mio post qui sotto.) Ecco perché raccomanderei contro questo approccio. L'approccio con Paint.getTextBounds()sembra funzionare in modo più accurato.
andreas1724,

217

Centra con Paint.getTextBounds () :

inserisci qui la descrizione dell'immagine

private Rect r = new Rect();

private void drawCenter(Canvas canvas, Paint paint, String text) {
    canvas.getClipBounds(r);
    int cHeight = r.height();
    int cWidth = r.width();
    paint.setTextAlign(Paint.Align.LEFT);
    paint.getTextBounds(text, 0, text.length(), r);
    float x = cWidth / 2f - r.width() / 2f - r.left;
    float y = cHeight / 2f + r.height() / 2f - r.bottom;
    canvas.drawText(text, x, y, paint);
}
  • Paint.Align.CENTER non significa che il punto di riferimento del testo sia centrato verticalmente. Il punto di riferimento è sempre sulla linea di base. Quindi, perché non usare Paint.Align.LEFT ? Devi comunque calcolare il punto di riferimento.

  • Paint.descent () ha lo svantaggio di non considerare il testo reale. Paint.descent () recupera lo stesso valore, indipendentemente dal fatto che il testo contenga o meno lettere con discendenza. Ecco perché uso invece r.bottom .

  • Ho avuto alcuni problemi con Canvas.getHeight () se API <16. Ecco perché uso Canvas.getClipBounds (Rect) . (Non utilizzare Canvas.getClipBounds (). GetHeight () poiché alloca memoria per un Rect .)

  • Per motivi di prestazioni, è necessario allocare gli oggetti prima che vengano utilizzati in onDraw () . Come drawCenter () verrà chiamato all'interno di onDraw () l'oggetto Rect r viene preallocato come campo.


Ho provato a inserire il codice delle due risposte principali nel mio codice (agosto 2015) e ho creato uno screenshot per confrontare i risultati:

testo centrato tre versioni

Il testo dovrebbe essere centrato all'interno del rettangolo rosso pieno. Il mio codice produce il testo bianco, gli altri due codici producono del tutto il testo grigio (in realtà sono gli stessi, sovrapposti). Il testo grigio è un po 'troppo basso e due molto a destra.

Ecco come ho fatto il test:

import android.app.Activity;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Typeface;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;

class MyView extends View {

    private static String LABEL = "long";
    private static float TEXT_HEIGHT_RATIO = 0.82f;

    private FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(0, 0);
    private Rect r = new Rect();
    private Paint paint = new Paint();
    private Paint rectPaint = new Paint();

    public MyView(Context context) {
        super(context);
    }

    private void drawTextBounds(Canvas canvas, Rect rect, int x, int y) {
        rectPaint.setColor(Color.rgb(0, 0, 0));
        rectPaint.setStyle(Paint.Style.STROKE);
        rectPaint.setStrokeWidth(3f);
        rect.offset(x, y);
        canvas.drawRect(rect, rectPaint);
    }

    // andreas1724 (white color):
    private void draw1(Canvas canvas, Paint paint, String text) {
        paint.setTextAlign(Paint.Align.LEFT);
        paint.setColor(Color.rgb(255, 255, 255));
        canvas.getClipBounds(r);
        int cHeight = r.height();
        int cWidth = r.width();
        paint.getTextBounds(text, 0, text.length(), r);
        float x = cWidth / 2f - r.width() / 2f - r.left;
        float y = cHeight / 2f + r.height() / 2f - r.bottom;
        canvas.drawText(text, x, y, paint);
        drawTextBounds(canvas, r, (int) x, (int) y);
    }

    // Arun George (light green color):
    private void draw2(Canvas canvas, Paint textPaint, String text) {
        textPaint.setTextAlign(Paint.Align.CENTER);
        textPaint.setColor(Color.argb(100, 0, 255, 0));
        int xPos = (canvas.getWidth() / 2);
        int yPos = (int) ((canvas.getHeight() / 2) - ((textPaint.descent() + textPaint.ascent()) / 2));
        canvas.drawText(text, xPos, yPos, textPaint);
    }

    // VinceStyling (light blue color):
    private void draw3(Canvas yourCanvas, Paint mPaint, String pageTitle) {
        mPaint.setTextAlign(Paint.Align.LEFT);
        mPaint.setColor(Color.argb(100, 0, 0, 255));
        r = yourCanvas.getClipBounds();
        RectF bounds = new RectF(r);
        bounds.right = mPaint.measureText(pageTitle, 0, pageTitle.length());
        bounds.bottom = mPaint.descent() - mPaint.ascent();
        bounds.left += (r.width() - bounds.right) / 2.0f;
        bounds.top += (r.height() - bounds.bottom) / 2.0f;
        yourCanvas.drawText(pageTitle, bounds.left, bounds.top - mPaint.ascent(), mPaint);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        int margin = 10;
        int width = w - 2 * margin;
        int height = h - 2 * margin;
        params.width = width;
        params.height = height;
        params.leftMargin = margin;
        params.topMargin = margin;
        setLayoutParams(params);
        paint.setTextSize(height * TEXT_HEIGHT_RATIO);
        paint.setAntiAlias(true);
        paint.setTypeface(Typeface.create(Typeface.SERIF, Typeface.BOLD_ITALIC));
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawColor(Color.rgb(255, 0, 0));
        draw1(canvas, paint, LABEL);
        draw2(canvas, paint, LABEL);
        draw3(canvas, paint, LABEL);
    }
}

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setRequestedOrientation (ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
        FrameLayout container = new FrameLayout(this);
        container.setLayoutParams(new ViewGroup.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.MATCH_PARENT));
        container.addView(new MyView(this));
        setContentView(container);
    }
}

1
Grazie mille .. La tua logica mi ha davvero aiutato molto.
Sujay ONU

Grazie mille .. Anche la tua logica mi ha aiutato molto!
LiuWenbin_NO.

Questa è l'unica risposta che centra veramente il testo.
Joery

64

L'allineamento verticale è difficile perché sono avvenute la discesa e l'ascesa del testo, molti ragazzi hanno usato Paint.getTextBounds () per recuperare TextWidth e TextHeight, ma non rende molto il centro di testo. Qui possiamo usare Paint.measureText () per calcolare TextWidth, TextHeight che semplicemente sottraggiamo con discesa e salita, quindi abbiamo ottenuto l'approccio più TextSize, il seguente lavoro è abbastanza facile l'uno per l'altro.

// the Paint instance(should be assign as a field of class).
Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setTextSize(getResources().getDimension(R.dimen.btn_textsize));

// the display area.
Rect areaRect = new Rect(0, 0, 240, 60);

// draw the background style (pure color or image)
mPaint.setColor(Color.BLACK);
yourCanvas.drawRect(areaRect, mPaint);

String pageTitle = "文字小说";

RectF bounds = new RectF(areaRect);
// measure text width
bounds.right = mPaint.measureText(pageTitle, 0, pageTitle.length());
// measure text height
bounds.bottom = mPaint.descent() - mPaint.ascent();

bounds.left += (areaRect.width() - bounds.right) / 2.0f;
bounds.top += (areaRect.height() - bounds.bottom) / 2.0f;

mPaint.setColor(Color.WHITE);
yourCanvas.drawText(pageTitle, bounds.left, bounds.top - mPaint.ascent(), mPaint);

schermata catturata dal codice

A proposito, consigliamo vivamente di utilizzare RectF piuttosto che Rect perché le posizioni richiedono valori più precisi, nella mia esperienza, RectF ha fatto la deviazione superiore e inferiore solo un pixel sul dispositivo xhdpi, Rect sarebbe altri due.


Come scritto, il var "Paint" è confuso. Come viene assegnato? come fa a conoscere l'ascesa e la discesa del testo per bounds.bottom?
RoundSparrow hilltx

1
sì, ho ottimizzato la mia risposta per questo, per favore dai un'occhiata.
VinceStyling,

Grazie per avermi risparmiato tempo prezioso))
Andrey il

16

Il codice disegna il centro della linea di base del testo, al centro della vista. Al fine di centrare il testo ad un certo punto, x, y, è necessario calcolare il centro del testo, e mettere che in corrispondenza del punto.

Questo metodo disegna il testo centrato nel punto x, y. Se lo passi al centro della vista, disegna il testo centrato.

private void drawTextCentered(String text, int x, int y, Paint paint, Canvas canvas) {
    int xPos = x - (int)(paint.measureText(text)/2);
    int yPos = (int) (y - ((textPaint.descent() + textPaint.ascent()) / 2)) ;

    canvas.drawText(text, xPos, yPos, textPaint);
}

@MarcioGranzotto è l' android.graphics.Paintessere usato per disegnare il testo
William Reed

4

Trovo che la migliore soluzione per centrare il testo sia la seguente:

textPaint.setTextAlign(Paint.Align.CENTER);
//textPaint is the Paint object being used to draw the text (it must be initialized beforehand)
float textY=center.y;
float textX=center.x; 
// in this case, center.x and center.y represent the coordinates of the center of the rectangle in which the text is being placed
canvas.drawText(text,textX,textY,textPaint);    `

Questo sembra esattamente il modo in cui l'interrogante ha cercato di centrare il testo. Il testo non sarà centrato verticalmente perché Paint.Align.Center non significa che il punto di riferimento del testo sia centrato verticalmente.
andreas1724,

3

funziona per me da usare: textPaint.textAlign = Paint.Align.CENTER con textPaint.getTextBounds

private fun drawNumber(i: Int, canvas: Canvas, translate: Float) {
            val text = "$i"
            textPaint.textAlign = Paint.Align.CENTER
            textPaint.getTextBounds(text, 0, text.length, textBound)

            canvas.drawText(
                    "$i",
                    translate + circleRadius,
                    (height / 2 + textBound.height() / 2).toFloat(),
                    textPaint
            )
        }

il risultato è:

inserisci qui la descrizione dell'immagine


1

Creo un metodo per semplificare questo:

    public static void drawCenterText(String text, RectF rectF, Canvas canvas, Paint paint) {
    Paint.Align align = paint.getTextAlign();
    float x;
    float y;
    //x
    if (align == Paint.Align.LEFT) {
        x = rectF.centerX() - paint.measureText(text) / 2;
    } else if (align == Paint.Align.CENTER) {
        x = rectF.centerX();
    } else {
        x = rectF.centerX() + paint.measureText(text) / 2;
    }
    //y
    metrics = paint.getFontMetrics();
    float acent = Math.abs(metrics.ascent);
    float descent = Math.abs(metrics.descent);
    y = rectF.centerY() + (acent - descent) / 2f;
    canvas.drawText(text, x, y, paint);

    Log.e("ghui", "top:" + metrics.top + ",ascent:" + metrics.ascent
            + ",dscent:" + metrics.descent + ",leading:" + metrics.leading + ",bottom" + metrics.bottom);
}

rectF è l'area che vuoi disegnare il testo, tutto qui. Dettagli


1

Se stiamo utilizzando il layout statico

mStaticLayout = new StaticLayout(mText, mTextPaint, mTextWidth,
                Layout.Alignment.ALIGN_CENTER, 1.0f, 0, true);

Layout.Alignment.ALIGN_CENTER questo farà il trucco. Il layout statico ha anche molti altri vantaggi.

Riferimento: documentazione Android


1

Questo ha funzionato per me:

 paint.setTextAlign(Paint.Align.CENTER);
        int xPos = (newWidth / 2);
        int yPos = (newHeight / 2);
        canvas.drawText("Hello", xPos, yPos, paint);

se qualcuno dovesse riscontrare qualche problema, per favore fatemelo sapere


inizierà a scrivere il testo dal punto centrale ma l'intero testo non sarà al centro
M Shaban Ali,

1

Nel mio caso, non ho dovuto mettere il testo nel mezzo di una tela, ma in una ruota che gira. Anche se ho dovuto usare questo codice per avere successo:

fun getTextRect(textSize: Float, textPaint: TextPaint, string: String) : PointF {
    val rect = RectF(left, top, right, bottom)
    val rectHeight = Rect()
    val cx = rect.centerX()
    val cy = rect.centerY()

    textPaint.getTextBounds(string, 0, string.length, rectHeight)
    val y = cy + rectHeight.height()/2
    val x = cx - textPaint.measureText(string)/2

    return PointF(x, y)
}

Quindi chiamo questo metodo dalla classe View:

private fun drawText(canvas: Canvas, paint: TextPaint, text: String, string: String) {
    val pointF = getTextRect(paint.textSize, textPaint, string)
    canvas.drawText(text, pointF!!.x, pointF.y, paint)
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.