2010-09-06 13 views
90

¿Cualquier forma directa de medir el alto del texto? La forma en que lo estoy haciendo ahora es usar el measureText() de Paint para obtener el ancho, y luego, por prueba y error, encontrar un valor para obtener una altura aproximada. También he estado jugando con FontMetrics, pero todos estos parecen métodos aproximados que apestan.Medición de la altura del texto que se dibujará en Canvas (Android)

Estoy tratando de escalar cosas para diferentes resoluciones. Puedo hacerlo, pero termino con un código increíblemente detallado con muchos cálculos para determinar los tamaños relativos. ¡Lo odio! Tiene que haber una mejor manera.

Respuesta

117

¿Qué hay de paint.getTextBounds() (método de objeto)

+1

Esto produce resultados muy extraños, cuando evalúo la altura de un texto. Un texto corto da como resultado una altura de 12, mientras que un texto REALMENTE largo da como resultado una altura de 16 (dado un tamaño de letra de 16). No tiene sentido para mí (android 2.3.3) – AgentKnopf

+34

La varianza en altura es donde tienes descendentes en el texto, es decir'Alto' es más alto que 'Bajo' debido a la parte del g debajo de la línea – FrinkTheBrave

1

debe utilizar Rect.width() y Rect.Height() la que regresó de getTextBounds() lugar. Funciona para mi.

+2

No si se trata de múltiples segmentos de texto. El motivo está en mi respuesta anterior. –

74

@ respuesta de bramp es correcto - en parte, ya que no menciona que los límites calculados serán el rectángulo mínimo que contiene el texto completo con coordenadas iniciales implícitos de 0, 0.

Esto significa, que la la altura de, por ejemplo, "Py" será diferente de la altura de "py" o "hi" u "oi" o "aw" porque, en píxeles, requieren diferentes alturas.

Esto de ninguna manera es equivalente a FontMetrics en java clásico.

Si bien el ancho de un texto no es muy molesto, la altura sí lo es.

En particular, si necesita alinear verticalmente el texto dibujado, intente obtener los límites del texto "a" (sin comillas), en lugar de usar el texto que desea dibujar. funciona para mí ...

Esto es lo que quiero decir:

Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.LINEAR_TEXT_FLAG); 

paint.setStyle(Paint.Style.FILL); 
paint.setColor(color); 
paint.setTextAlign(Paint.Align.CENTER); 
paint.setTextSize(textSize); 

Rect bounds = new Rect(); 
paint.getTextBounds("a", 0, 1, bounds); 

buffer.drawText(this.myText, canvasWidth >> 1, (canvasHeight + bounds.height()) >> 1, paint); 
// remember x >> 1 is equivalent to x/2, but works much much faster 

centro verticalmente alinear verticalmente el texto significa centrar alinear el rectángulo delimitador - que es diferente para diferentes textos (gorras, largas cartas, etc.). Pero lo que realmente queremos hacer es alinear las líneas de base de los textos renderizados, de modo que no parezcan elevados ni estriados. Entonces, mientras sepamos el centro de la letra más pequeña ("a", por ejemplo), podemos reutilizar su alineación para el resto de los textos. Esto alineará todos los textos al igual que la línea de base y los alineará.

+18

No he visto 'x >> 1' por años. Upvoting solo por eso :) – keaukraine

+50

Un buen compilador moderno verá 'x/2' y lo optimizará a' x >> 1' –

+31

@keaukraine 'x/2' es mucho más amigable cuando lee el código, teniendo en cuenta el comentario de Chris. – d3dave

2

Simplemente puede obtener el tamaño de texto para un objeto Paint utilizando el método getTextSize(). Por ejemplo:

Paint mTextPaint = new Paint (Paint.ANTI_ALIAS_FLAG); 
//use densityMultiplier to take into account different pixel densities 
final float densityMultiplier = getContext().getResources() 
      .getDisplayMetrics().density; 
mTextPaint.setTextSize(24.0f*densityMultiplier); 

//... 

float size = mTextPaint.getTextSize(); 
+0

¿De dónde viene el '24.0f'? – Erigami

+0

24.0f es solo un ejemplo para un tamaño de texto – moondroid

2

usted podría utilizar la clase android.text.StaticLayout para especificar los límites requeridos y luego llamar getHeight(). Puede dibujar el texto (contenido en el diseño) llamando a su método draw(Canvas).

0

Si alguien todavía tiene un problema, este es mi código.

Tengo una vista personalizada que es cuadrada (ancho = alto) y quiero asignarle un carácter. onDraw() muestra cómo obtener la altura del personaje, aunque no lo estoy usando. El personaje se mostrará en el medio de la vista.

public class SideBarPointer extends View { 

    private static final String TAG = "SideBarPointer"; 

    private Context context; 
    private String label = ""; 
    private int width; 
    private int height; 

    public SideBarPointer(Context context) { 
     super(context); 
     this.context = context; 
     init(); 
    } 

    public SideBarPointer(Context context, AttributeSet attrs) { 
     super(context, attrs); 
     this.context = context; 
     init(); 
    } 

    public SideBarPointer(Context context, AttributeSet attrs, int defStyle) { 
     super(context, attrs, defStyle); 
     this.context = context; 
     init(); 
    } 

    private void init() { 
//  setBackgroundColor(0x64FF0000); 
    } 

    @Override 
    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec){ 
     super.onMeasure(widthMeasureSpec, heightMeasureSpec); 

     height = this.getMeasuredHeight(); 
     width = this.getMeasuredWidth(); 

     setMeasuredDimension(width, width); 
    } 

    protected void onDraw(Canvas canvas) { 
     float mDensity = context.getResources().getDisplayMetrics().density; 
     float mScaledDensity = context.getResources().getDisplayMetrics().scaledDensity; 

     Paint previewPaint = new Paint(); 
     previewPaint.setColor(0x0C2727); 
     previewPaint.setAlpha(200); 
     previewPaint.setAntiAlias(true); 

     Paint previewTextPaint = new Paint(); 
     previewTextPaint.setColor(Color.WHITE); 
     previewTextPaint.setAntiAlias(true); 
     previewTextPaint.setTextSize(90 * mScaledDensity); 
     previewTextPaint.setShadowLayer(5, 1, 2, Color.argb(255, 87, 87, 87)); 

     float previewTextWidth = previewTextPaint.measureText(label); 
//  float previewTextHeight = previewTextPaint.descent() - previewTextPaint.ascent(); 
     RectF previewRect = new RectF(0, 0, width, width); 

     canvas.drawRoundRect(previewRect, 5 * mDensity, 5 * mDensity, previewPaint); 
     canvas.drawText(label, (width - previewTextWidth)/2, previewRect.top - previewTextPaint.ascent(), previewTextPaint); 

     super.onDraw(canvas); 
    } 

    public void setLabel(String label) { 
     this.label = label; 
     Log.e(TAG, "Label: " + label); 

     this.invalidate(); 
    } 
} 
+2

-1 para asignaciones en onDraw(): generaría una tonelada de beneficios de rendimiento si declarara los campos en la clase (inicie en el constructor) y los vuelva a usar en onDraw(). – zoltish

+0

@zoltish Gracias hermano por el comentario pero voto abajo? !! generalmente utiliza respuestas duplicadas/incorrectas, no respuestas relativas o incluso informativas. de todos modos tienes razón y es el punto correcto para aquellos que están usando mi sugerencia. – Hesam

13

El alto es el tamaño de texto que ha establecido en la variable Paint.

Otra forma de averiguar la altura es

mPaint.getTextSize(); 
67

Hay diferentes maneras de medir la altura en función de lo que necesita.

getTextBounds

Si usted está haciendo algo así como el centrado, precisamente, una pequeña cantidad de texto fijo, es probable que quieren getTextBounds. Usted puede obtener el rectángulo delimitador como esto

Rect bounds = new Rect(); 
mTextPaint.getTextBounds(mText, 0, mText.length(), bounds); 
int height = bounds.height(); 

Como se puede ver por las siguientes imágenes, diferentes cadenas darán diferentes alturas (en rojo).

enter image description here

Estas alturas diferentes podrían ser una desventaja en algunas situaciones en las que sólo tiene una altura constante independientemente de lo que el texto es. Ver la siguiente sección.

Paint.FontMetrics

se puede calcular la altura de la fuente de las medidas de fuente. La altura es siempre la misma porque se obtiene de la fuente, no de una cadena de texto en particular.

Paint.FontMetrics fm = mTextPaint.getFontMetrics(); 
float height = fm.descent - fm.ascent; 

La línea de base es la línea en la que se encuentra el texto. El descenso generalmente es lo más lejos que un personaje irá por debajo de la línea y el ascenso generalmente es lo más lejos que un personaje irá por encima de la línea. Para obtener la altura, debes restar el ascenso porque es un valor negativo. (La línea base es y=0 y y descrece en la pantalla.)

Mire la siguiente imagen. Las alturas para ambas cadenas son 234.375.

enter image description here

Si desea que la altura de la línea en lugar de sólo la altura del texto, se puede hacer lo siguiente:

float height = fm.bottom - fm.top + fm.leading; // 265.4297 

Estos son los bottom y top de la línea. El principal (espaciado entre líneas) es generalmente cero, pero debe agregarlo de todos modos.

Las imágenes de arriba provienen de this project. Puedes jugar con él para ver cómo funciona Font Metrics.

StaticLayout

Para medir la altura de texto de varias líneas se debe utilizar un StaticLayout. Hablé de ello con cierto detalle en this answer, pero la forma básica para obtener esta altura es la siguiente:

String text = "This is some text. This is some text. This is some text. This is some text. This is some text. This is some text."; 

TextPaint myTextPaint = new TextPaint(); 
myTextPaint.setAntiAlias(true); 
myTextPaint.setTextSize(16 * getResources().getDisplayMetrics().density); 
myTextPaint.setColor(0xFF000000); 

int width = 200; 
Layout.Alignment alignment = Layout.Alignment.ALIGN_NORMAL; 
float spacingMultiplier = 1; 
float spacingAddition = 0; 
boolean includePadding = false; 

StaticLayout myStaticLayout = new StaticLayout(text, myTextPaint, width, alignment, spacingMultiplier, spacingAddition, includePadding); 

float height = myStaticLayout.getHeight(); 
+0

Buena explicación. ¿De qué aplicación son las capturas de pantalla? –

+1

@MichealJohnson, agregué la aplicación como un [proyecto de GitHub aquí] (https://github.com/suragch/AndroidFontMetrics). – Suragch

Cuestiones relacionadas