studio programacion herramientas fundamentos con avanzado aplicaciones java android android-activity android-canvas drawtext

java - programacion - manual de android en pdf



Texto de Android Center en lienzo (7)

Estoy tratando de mostrar un texto usando el siguiente código. El problema es que el texto no está centrado horizontalmente. Cuando establezco las coordenadas para drawText , establece la parte inferior del texto en esta posición. Me gustaría que el texto se dibuje para que el texto se centre también horizontalmente.

Esta es una imagen para mostrar mi problema aún más:

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


Alinearse verticalmente es difícil porque se produjo el descenso y el ascenso de texto, muchos chicos usaron Paint.getTextBounds () para recuperar el TextWidth y TextHeight, pero no hace que el texto se centre demasiado. Aquí podemos usar Paint.measureText () para calcular el TextWidth, el TextHeight que simplemente hacemos restando con el descenso y el ascenso, luego conseguimos el mayor acercamiento al TextSize, el siguiente trabajo es bastante fácil el uno para el otro.

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

Por cierto, recomendamos usar RectF en lugar de Rect porque las posiciones necesitan valores más precisos, en mi experiencia, RectF realizó la desviación superior e inferior de un píxel en el dispositivo xhdpi, Rect sería dos más.


Centro con 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 no significa que el punto de referencia del texto esté centrado verticalmente. El punto de referencia siempre está en la línea de base. Entonces, ¿por qué no usar Paint.Align.LEFT ? Tienes que calcular el punto de referencia de todos modos.

  • Paint.descent () tiene la desventaja de que no tiene en cuenta el texto real. Paint.descent () recupera el mismo valor, independientemente de si el texto contiene letras con descensos o no. Es por eso que uso r.bottom en su lugar.

  • He tenido algunos problems con Canvas.getHeight () si API <16. Es por eso que uso Canvas.getClipBounds (Rect) en su lugar. (No use Canvas.getClipBounds (). GetHeight () ya que asigna memoria para un Rect .)

  • Por razones de rendimiento, debe asignar objetos antes de que se utilicen en onDraw () . Como se llamará a drawCenter () dentro de onDraw () el objeto Rect r se preasignará como un campo aquí.

Traté de poner el código de las dos respuestas principales en mi propio código (agosto de 2015) e hice una captura de pantalla para comparar los resultados:

El texto debe estar centrado dentro del rectángulo lleno de rojo. Mi código produce el texto blanco, los otros dos códigos producen en conjunto el texto gris (en realidad son iguales, se superponen). El texto gris es un poco demasiado bajo y dos mucho más a la derecha.

Así es como hice la prueba:

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


Creé un método para simplificar esto:

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 es el área que desea dibujar el texto, eso es todo. Details


Encuentro que la mejor solución para centrar el texto es la siguiente:

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


Pruebe lo siguiente:

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


Si estamos usando el diseño estático

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

Layout.Alignment.ALIGN_CENTER esto hará el truco. El diseño estático también tiene muchas otras ventajas.

Referencia: documentación de Android


Su código dibuja el centro de la línea base del texto, en el centro de la vista. Para centrar el texto en algún punto, x, y, debe calcular el centro del texto y ponerlo en el punto.

Este método dibujará texto centrado en el punto x, y. Si lo pasa al centro de su vista, dibujará el texto centrado.

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