Вопрос по java, android, android-activity, android-canvas, drawtext – Android Center текст на холсте

159

Я пытаюсь отобразить текст, используя приведенный ниже код. Проблема в том, что текст не центрирован по горизонтали. Когда я устанавливаю координаты дляdrawText, он устанавливает нижнюю часть текста в этой позиции. Я хотел бы, чтобы текст был нарисован так, чтобы текст был также центрирован по горизонтали.

Это изображение, чтобы показать мою проблему дальше:

Screenshot

@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);
}
@Sebastian Эй, у тебя еще есть эта ссылка? S.Lukas
@ S.Lukas hhahaha BOTJr.
Приятель! Пожалуйста, отметьте, что ваша ссылка на изображение является NSFW! Я не хочу быть ханжеским, но мне не нужны объявления с топлесс женщинами, появляющимися на моем экране в офисе. Michael Scheper
@MichaelScheper Извините, я обновил ссылку! Sebastian
Я бы не объявил ваш объект рисования внутри вашего события onDraw. Он воссоздается каждый раз, когда перерисовывается. Подумайте о том, чтобы сделать его переменной частного класса. Christopher Rathgeb

Ваш Ответ

7   ответов
1

Если мы используем статический макет

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

Layout.Alignment.ALIGN_CENTER это сделает свое дело. Статическая компоновка также имеет много других преимуществ.

Ссылка:Документация Android

330

Попробуйте следующее:

 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);
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit ExceededPaint.descent()Error: User Rate Limit ExceededPaint.ascent()Error: User Rate Limit ExceededPaint.getTextBounds()Error: User Rate Limit ExceededPaint.descent()Error: User Rate Limit ExceededPaint.ascent()Error: User Rate Limit ExceededPaint.getTextBounds()Error: User Rate Limit Exceeded
Error: User Rate Limit ExceededcastError: User Rate Limit Exceededfloat halfLength = text.length() / 2f;Error: User Rate Limit Exceededpromotion.
0

Это сработало для меня:

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

если кто-нибудь обнаружит какие-либо проблемы, пожалуйста, дайте мне знать

1

Я создаю метод, чтобы упростить это:

    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 - это область, в которой вы хотите нарисовать текст, вот и все. подробности

13

Ваш код рисует центр базовой линии текста, в центре представления. Чтобы центрировать текст в некоторой точке, x, y, вам нужно вычислить центр текста и поместитьthat в точке.

Этот метод будет рисовать текст по центру в точке x, y. Если вы передадите его центру своего представления, текст будет отцентрирован.

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);
}
Error: User Rate Limit ExceededtextPaintError: User Rate Limit Exceeded
3

Я считаю, что лучшее решение для центрирования текста заключается в следующем:

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);    `
Error: User Rate Limit ExceededPaint.Align.CenterError: User Rate Limit Exceeded
169

Центр сPaint.getTextBounds():

enter image description here

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 doesn't mean that the reference point of the text is vertically centered. The reference point is always on the baseline. So, why not use Paint.Align.LEFT? You have to calculate the reference point anyway.

  • Paint.descent() has the disadvantage, that it doesn't consider the real text. Paint.descent() retrieves the same value, regardless of whether the text contains letters with descents or not. That's why I use r.bottom instead.

  • I have had some problems with Canvas.getHeight() if API < 16. That's why I use Canvas.getClipBounds(Rect) instead. (Do not use Canvas.getClipBounds().getHeight() as it allocates memory for a Rect.)

  • For reasons of performance, you should allocate objects before they are used in onDraw(). As drawCenter() will be called within onDraw() the object Rect r is preallocated as a field here.


Я попытался поместить код двух лучших ответов в свой собственный код (август 2015 года) и сделал скриншот для сравнения результатов:

text centered three versions

Текст должен быть в центре красного прямоугольника. Мой код создает белый текст, два других кода - серый текст (они на самом деле совпадают, накладываются друг на друга). Серый текст слишком низок, а два справа.

Вот как я сделал тест:

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);
    }
}
Error: User Rate Limit Exceeded

Похожие вопросы