Medición de la altura del texto a dibujar en lienzo (Android)

Cualquier forma directa de medir la altura del texto? La manera que lo estoy haciendo ahora es usando el measureText() Paint para obtener el ancho, luego por ensayo y error encontrando un valor para obtener una altura aproximada. También he estado jugando con FontMetrics , pero todos estos parecen métodos aproximados que chupan.

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

¿Qué pasa con Paint.getTextBounds ()

La respuesta de @ bramp es correcta – en parte, en que no menciona que los límites calculados serán el rectángulo mínimo que contiene el texto totalmente con coordenadas iniciales implícitas de 0, 0.

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

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

Mientras que la anchura de un texto no es mucho de un dolor, la altura es.

En particular, si necesita alinear verticalmente el texto dibujado, trate de obtener los límites del texto "a" (sin comillas), en lugar de utilizar el texto que desea dibujar. Funciona para mi…

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 

Al centro vertical alinear el texto significa alinear verticalmente el rectángulo delimitador – que es diferente para diferentes textos (mayúsculas, letras largas, etc). Pero lo que realmente queremos hacer es también alinear las líneas de base de los textos renderizados, de modo que no aparezcan elevados o ranurados. Así que, mientras conozcamos el centro de la letra más pequeña ("a" por ejemplo) entonces podemos reutilizar su alineación para el resto de los textos. Esto centrará la alineación de todos los textos, así como la línea de base de alinearlos.

Hay diferentes maneras de medir la altura dependiendo de lo que usted necesita.

GetTextBounds

Si está haciendo algo como centrar precisamente una pequeña cantidad de texto fijo, probablemente querrá getTextBounds . Puedes obtener el rectángulo delimitador como este

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

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

Introduzca aquí la descripción de la imagen

Estas alturas diferentes podrían ser una desventaja en algunas situaciones cuando sólo necesita una altura constante, no importa lo que el texto es. Vea la siguiente sección.

Paint.FontMetrics

Puede calcular la altura de la fuente de las métricas 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 es generalmente el más lejano un carácter va debajo de la línea y el ascenso es generalmente el más lejano un carácter va por encima de la línea. Para obtener la altura hay que restar el ascenso porque es un valor negativo. (La línea de base es y=0 y desciende por la pantalla.)

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

Introduzca aquí la descripción de la imagen

Si desea que la altura de la línea no sea sólo la altura del texto, puede hacer lo siguiente:

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

Estos son el bottom y la bottom top de la línea. El líder (interline espaciamiento) es generalmente cero, pero debe agregar de todos modos.

Las imágenes de arriba provienen de este proyecto . Puedes jugar con él para ver cómo funcionan las métricas de fuentes.

StaticLayout

Para medir la altura del texto de varias líneas, debe utilizar StaticLayout . Hablé de ello en detalle en esta respuesta , pero la forma básica de conseguir 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(); 

La altura es el tamaño de texto que ha establecido en la variable Paint.

Otra forma de averiguar la altura es

 mPaint.getTextSize(); 

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

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

Debe utilizar Rect.width() y Rect.Height() que devuelven getTextBounds() lugar. Funciona para mi.

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

Tengo una vista personalizada que es cuadrado (width = height) y quiero asignarle un carácter. onDraw() muestra cómo obtener la altura del carácter, aunque no lo estoy usando. El carácter aparecerá en el centro 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(); } } 
  • Multi-nivel ExpandableListView en Android
  • EditText no envolverá su texto
  • HasStableIds () en ListView expandible?
  • Animación giratoria androide
  • Android: en el interruptor de desplazamiento entre Vistas / Actividades / Fragmentos
  • Android WebView no sólo de vídeo audio
  • Diferencia entre View y ViewGroup en Android
  • Mostrar enormes imágenes en Android
  • Agregar vista dinámica mediante WindowManager.addView
  • WebView de Android - Dithering / Cambios al tacto
  • Arrastrar y soltar iconos a la pantalla de inicio
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.