Текст Android-центра на canvasе

Я пытаюсь отобразить текст, используя приведенный ниже код. Проблема в том, что текст не центрирован по горизонтали. Когда я устанавливаю координаты 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); } 

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

  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); 

Центр с 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); } 
  • Paint.Align.CENTER не означает, что опорная точка текста вертикально центрирована. Контрольная точка всегда находится на базовой линии. Итак, почему бы не использовать Paint.Align.LEFT ? Вы все равно должны вычислить контрольную точку.

  • Paint.descent () имеет тот недостаток, что он не учитывает реальный текст. Paint.descent () извлекает одно и то же значение, независимо от того, содержит ли текст буквы со спусками или нет. Вот почему я использую r.bottom вместо этого.

  • У меня были некоторые проблемы с Canvas.getHeight (), если API <16. Вот почему я использую Canvas.getClipBounds (Rect) . (Не используйте Canvas.getClipBounds (). GetHeight (), поскольку он выделяет память для Rect .)

  • По соображениям производительности вы должны выделить объекты, прежде чем они будут использоваться в onDraw () . Поскольку drawCenter () будет вызываться внутри onDraw (), объект Rect r предварительно распределяется как поле здесь.


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

текст сосредоточен на трех версиях

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

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

 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); } } 

Выравнивание по вертикали затруднено, потому что произошло спуск текста и восхождение, многие ребята использовали 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); 

экран, снятый кодом

Кстати, мы настоятельно рекомендуем использовать RectF, а не Rect, потому что позиции требуют более точных значений. По моему опыту, RectF выполнил верхнее и нижнее отклонение только на один пиксель на устройстве xhdpi, Rect будет еще двумя.

Ваш код рисует центр базовой линии текста в центре представления. Чтобы центрировать текст в какой-то момент, 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); } 

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

 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); ` 

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

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

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

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

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

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

  • Как использовать первую букву слова в строке с использованием Java?
  • как конвертировать миллисекунды в формат даты в android?
  • Лучший способ реализовать View.OnClickListener в android
  • Дублированные записи в ListView
  • Как сгруппировать сетку 3x3 переключателей?
  • Android для выбора цвета для включения в активность
  • Каковы подводные камни Java noob?
  • Преобразование Json Array в обычный Java-массив
  • Как я могу избежать задержек сбора мусора в Java-играх? (Лучшие практики)
  • Правильный способ реализации равного контракта
  • Время соединения истекло. Зачем?
  • Давайте будем гением компьютера.