画布上的Android中心文字

Seb*_*ian 180 java android drawtext android-canvas android-activity

我正在尝试使用下面的代码显示文本.问题是文本不是水平居中的.当我设置坐标时drawText,它会在此位置设置文本的底部.我希望绘制文本,以便文本也水平居中.

这是一张进一步显示我的问题的图片:

截图

@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);
}
Run Code Online (Sandbox Code Playgroud)

Aru*_*rge 353

请尝试以下方法:

 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);
Run Code Online (Sandbox Code Playgroud)

  • paj7777,如果设置textPaint.setTextAlign(Align.CENTER)则没有必要; (57认同)
  • 很好的答案.对我来说,我使用了以下内容,因为我需要将文本水平地完全居中,而不是从中心位置开始的文本:int xPos =(Width - textPaint.TextSize*Math.Abs​​(_text.Length/2))/ 2; 不确定是否有更好的方法来实现这一目标. (10认同)
  • 我在下面的答案中比较了这种方法(= center with `Paint.descent()` 和 `Paint.ascent()`)与使用 `Paint.getTextBounds()` 居中文本的方法。`Paint.descent()` 和 `Paint.ascent()` 不考虑实际文本。(您可以在我下面帖子中的屏幕截图中识别出这种不准确之处。)这就是我建议不要使用这种方法的原因。`Paint.getTextBounds()` 的方法似乎更准确。 (2认同)

and*_*724 192

使用Paint.getTextBounds()进行居中:

在此输入图像描述

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);
}
Run Code Online (Sandbox Code Playgroud)
  • Paint.Align.CENTER并不意味着文本的参考点是垂直居中的.参考点始终位于基线上.那么,为什么不使用Paint.Align.LEFT?无论如何,你必须计算参考点.

  • Paint.descent()有缺点,它不考虑真实文本.无论文本是否包含带有下降的字母,Paint.descent()都会检索相同的值.这就是我使用r.bottom的原因.

  • 如果API <16,我在Canvas.getHeight()方面遇到了一些问题.这就是我使用Canvas.getClipBounds(Rect)的原因.(不要使用Canvas.getClipBounds().getHeight(),因为它为Rect分配内存.)

  • 出于性能原因,您应该在onDraw()中使用对象之前对其进行分配.由于drawCenter()将在onDraw()中调用,因此对象Rect r在此处预先分配为字段.


我试着将两个顶级答案的代码放入我自己的代码中(2015年8月)并制作了一个截图来比较结果:

文本集中了三个版本

文本应位于红色填充矩形的中心.我的代码产生白色文本,另外两个代码产生灰色文本(它们实际上是相同的,重叠的).灰色文字有点太低,右边有两个.

这就是我进行测试的方式:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)


Vin*_*ing 60

垂直对齐很困难,因为文本下降和上升发生了,许多人使用Paint.getTextBounds()来检索TextWidth和TextHeight,但它并没有使文本中心非常多.在这里我们可以使用Paint.measureText()来计算TextWidth,TextHeight我们只是用下降和上升来减去,然后我们得到了最多的方法TextSize,以下工作对彼此来说相当容易.

// 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);
Run Code Online (Sandbox Code Playgroud)

屏幕截图由代码

顺便说一句,我们强烈建议使用RectF而不是Rect,因为位置需要更准确的值,根据我的经验,RectF在xhdpi设备上只做了一个像素的顶部和底部偏差,Rect将是两个.


Bor*_*kov 14

您的代码正在绘制文本基线的中心,位于视图的中心.为了在某些时候,X,Y居中文本,你需要计算文本的中心,并把在的位置.

此方法将绘制以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);
}
Run Code Online (Sandbox Code Playgroud)


Ser*_*aka 5

适合我使用: textPaint.textAlign = Paint.Align.CENTERtextPaint.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
            )
        }
Run Code Online (Sandbox Code Playgroud)

结果是:

在此输入图像描述