tamaño - modificar textview android studio
¿Cómo escalar/cambiar el tamaño del texto para que se ajuste a TextView? (14)
Aquí hay una solución que creé en función de otros comentarios. Esta solución le permite establecer el tamaño del texto en XML, que será el tamaño máximo y se ajustará para ajustarse a la altura de la vista. Tamaño de ajuste de TextView
private float findNewTextSize(int width, int height, CharSequence text) {
TextPaint textPaint = new TextPaint(getPaint());
float targetTextSize = textPaint.getTextSize();
int textHeight = getTextHeight(text, textPaint, width, targetTextSize);
while(textHeight > height && targetTextSize > mMinTextSize) {
targetTextSize = Math.max(targetTextSize - 1, mMinTextSize);
textHeight = getTextHeight(text, textPaint, width, targetTextSize);
}
return targetTextSize;
}
private int getTextHeight(CharSequence source, TextPaint paint, int width, float textSize) {
paint.setTextSize(textSize);
StaticLayout layout = new StaticLayout(source, paint, width, Alignment.ALIGN_NORMAL, mSpacingMult, mSpacingAdd, true);
return layout.getHeight();
}
Estoy intentando crear un método para cambiar el tamaño del texto de varias líneas en una TextView
texto, de modo que se ajuste dentro de los límites (tanto las dimensiones X e Y) de TextView
.
En este momento, tengo algo, pero todo lo que hace es redimensionar el texto de manera que solo la primera letra / carácter del texto llene las dimensiones de TextView
(es decir, solo la primera letra es visible, y es enorme). Necesito que se ajuste a todas las líneas del texto dentro de los límites de TextView.
Esto es lo que tengo hasta ahora:
public static void autoScaleTextViewTextToHeight(TextView tv)
{
final float initSize = tv.getTextSize();
//get the width of the view''s back image (unscaled)....
float minViewHeight;
if(tv.getBackground()!=null)
{
minViewHeight = tv.getBackground().getIntrinsicHeight();
}
else
{
minViewHeight = 10f;//some min.
}
final float maxViewHeight = tv.getHeight() - (tv.getPaddingBottom()+tv.getPaddingTop())-12;// -12 just to be sure
final String s = tv.getText().toString();
//System.out.println(""+tv.getPaddingTop()+"/"+tv.getPaddingBottom());
if(minViewHeight >0 && maxViewHeight >2)
{
Rect currentBounds = new Rect();
tv.getPaint().getTextBounds(s, 0, s.length(), currentBounds);
//System.out.println(""+initSize);
//System.out.println(""+maxViewHeight);
//System.out.println(""+(currentBounds.height()));
float resultingSize = 1;
while(currentBounds.height() < maxViewHeight)
{
resultingSize ++;
tv.setTextSize(resultingSize);
tv.getPaint().getTextBounds(s, 0, s.length(), currentBounds);
//System.out.println(""+(currentBounds.height()+tv.getPaddingBottom()+tv.getPaddingTop()));
//System.out.println("Resulting: "+resultingSize);
}
if(currentBounds.height()>=maxViewHeight)
{
//just to be sure, reduce the value
tv.setTextSize(resultingSize-1);
}
}
}
Creo que el problema está en el uso de tv.getPaint().getTextBounds(...)
. Siempre devuelve números pequeños para los límites de texto ... pequeños en relación con los tv.getWidth()
y tv.getHeight()
... incluso si el tamaño del texto es mucho mayor que el ancho o alto de TextView
.
Comprueba si mi solución te ayuda a:
Descubrí que esto funcionó bien para mí. ver: https://play.google.com/store/apps/details?id=au.id.rupert.chauffeurs_name_board&hl=en
Código fuente en http://www.rupert.id.au/chauffeurs_name_board/verson2.php
http://catchthecows.com/?p=72 y https://github.com/catchthecows/BigTextButton
Esto se basa en la respuesta de mattmook. Funcionó bien en algunos dispositivos, pero no en todos. Moví el cambio de tamaño al paso de medición, convertí el tamaño máximo de fuente en un atributo personalizado, tomé los márgenes en cuenta y extendí FrameLayout en lugar de LineairLayout.
public class ResizeView extends FrameLayout {
protected float max_font_size;
public ResizeView(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.getTheme().obtainStyledAttributes(
attrs,
R.styleable.ResizeView,
0, 0);
max_font_size = a.getDimension(R.styleable.ResizeView_maxFontSize, 30.0f);
}
public ResizeView(Context context) {
super(context);
}
@Override
protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
// Use the parent''s code for the first measure
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// Assume we only have one child and it is the text view to scale
final TextView textView = (TextView) getChildAt(0);
// Check if the default measure resulted in a fitting textView
LayoutParams childLayout = (LayoutParams) textView.getLayoutParams();
final int textHeightAvailable = getMeasuredHeight() - getPaddingTop() - getPaddingBottom() - childLayout.topMargin - childLayout.bottomMargin;
int textViewHeight = textView.getMeasuredHeight();
if (textViewHeight < textHeightAvailable) {
return;
}
final int textWidthSpec = MeasureSpec.makeMeasureSpec(
MeasureSpec.getSize(widthMeasureSpec) - getPaddingLeft() - getPaddingRight() - childLayout.leftMargin - childLayout.rightMargin,
MeasureSpec.EXACTLY);
final int textHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
for (float size = max_font_size; size >= 1.05f; size-=0.1f) {
textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, size);
textView.measure(textWidthSpec, textHeightSpec);
textViewHeight = textView.getMeasuredHeight();
if (textViewHeight <= textHeightAvailable) {
break;
}
}
}
}
Y esto en attrs.xml:
<declare-styleable name="ResizeView">
<attr name="maxFontSize" format="reference|dimension"/>
</declare-styleable>
Y finalmente usado así:
<PACKAGE_NAME.ui.ResizeView xmlns:custom="http://schemas.android.com/apk/res/PACKAGE_NAME"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="start|center_vertical"
android:padding="5dp"
custom:maxFontSize="@dimen/normal_text">
<TextView android:id="@+id/tabTitle2"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</PACKAGE_NAME.ui.ResizeView>
He jugado con esto durante bastante tiempo, tratando de corregir los tamaños de fuente en una amplia variedad de tabletas de 7 "(kindle fire, Nexus7 y algunas de bajo costo en China con pantallas de baja resolución) y dispositivos.
El enfoque que finalmente funcionó para mí es el siguiente. El "32" es un factor arbitrario que básicamente da más de 70 caracteres en una línea horizontal de tableta de 7 ", que es el tamaño de fuente que estaba buscando. Ajústalo en consecuencia.
textView.setTextSize(getFontSize(activity));
public static int getFontSize (Activity activity) {
DisplayMetrics dMetrics = new DisplayMetrics();
activity.getWindowManager().getDefaultDisplay().getMetrics(dMetrics);
// lets try to get them back a font size realtive to the pixel width of the screen
final float WIDE = activity.getResources().getDisplayMetrics().widthPixels;
int valueWide = (int)(WIDE / 32.0f / (dMetrics.scaledDensity));
return valueWide;
}
La biblioteca AutofitTextView de MavenCentral maneja esto muy bien. La fuente alojada en Github (1k + estrellas) en https://github.com/grantland/android-autofittextview
Agregue lo siguiente a su app/build.gradle
repositories {
mavenCentral()
}
dependencies {
compile ''me.grantland:autofittextview:0.2.+''
}
Habilite cualquier vista que extienda TextView en el código:
AutofitHelper.create(textView);
Habilite cualquier vista que extienda TextView en XML:
<me.grantland.widget.AutofitLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:singleLine="true"
/>
</me.grantland.widget.AutofitLayout>
Use el Widget incorporado en código o XML:
<me.grantland.widget.AutofitTextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:singleLine="true"
/>
Prueba esto...
tv.setText("Give a very large text anc check , this xample is very usefull");
countLine=tv.getLineHeight();
System.out.println("LineCount " + countLine);
if (countLine>=40){
tv.setTextSize(15);
}
Pude responder mi propia pregunta usando el siguiente código (ver a continuación), pero mi solución fue muy específica para la aplicación. Por ejemplo, esto probablemente solo se verá bien y / o funcionará para un TextView con un tamaño de aprox. 1/2 de la pantalla (con un margen superior de 40px y márgenes laterales de 20px ... sin margen inferior).
Sin embargo, utilizando este enfoque, puede crear su propia implementación similar. El método estático básicamente solo mira el número de caracteres y determina un factor de escala para aplicar al tamaño de texto del TextView, y luego incrementa el tamaño del texto hasta la altura total (una altura estimada - usando el ancho del texto, el texto alto, y el ancho del TextView) está justo debajo del TextView. Los parámetros necesarios para determinar el factor de escala (es decir, las declaraciones if / else if) se establecieron mediante adivinar y verificar. Es probable que tenga que jugar con los números para que funcione para su aplicación particular.
Esta no es la solución más elegante, aunque fue fácil de codificar y funciona para mí. ¿Alguien tiene un mejor enfoque?
public static void autoScaleTextViewTextToHeight(final TextView tv, String s)
{
float currentWidth=tv.getPaint().measureText(s);
int scalingFactor = 0;
final int characters = s.length();
//scale based on # of characters in the string
if(characters<5)
{
scalingFactor = 1;
}
else if(characters>=5 && characters<10)
{
scalingFactor = 2;
}
else if(characters>=10 && characters<15)
{
scalingFactor = 3;
}
else if(characters>=15 && characters<20)
{
scalingFactor = 3;
}
else if(characters>=20 && characters<25)
{
scalingFactor = 3;
}
else if(characters>=25 && characters<30)
{
scalingFactor = 3;
}
else if(characters>=30 && characters<35)
{
scalingFactor = 3;
}
else if(characters>=35 && characters<40)
{
scalingFactor = 3;
}
else if(characters>=40 && characters<45)
{
scalingFactor = 3;
}
else if(characters>=45 && characters<50)
{
scalingFactor = 3;
}
else if(characters>=50 && characters<55)
{
scalingFactor = 3;
}
else if(characters>=55 && characters<60)
{
scalingFactor = 3;
}
else if(characters>=60 && characters<65)
{
scalingFactor = 3;
}
else if(characters>=65 && characters<70)
{
scalingFactor = 3;
}
else if(characters>=70 && characters<75)
{
scalingFactor = 3;
}
else if(characters>=75)
{
scalingFactor = 5;
}
//System.out.println(((int)Math.ceil(currentWidth)/tv.getWidth()+scalingFactor));
//the +scalingFactor is important... increase this if nec. later
while((((int)Math.ceil(currentWidth)/tv.getWidth()+scalingFactor)*tv.getTextSize())<tv.getHeight())
{
tv.setTextSize(TypedValue.COMPLEX_UNIT_SP, tv.getTextSize()+0.25f);
currentWidth=tv.getPaint().measureText(s);
//System.out.println(((int)Math.ceil(currentWidth)/tv.getWidth()+scalingFactor));
}
tv.setText(s);
}
Gracias.
Si su único requisito es que el texto se divida automáticamente y continúe en la siguiente línea y la altura no es importante, solo tiene que hacerlo así.
<TextView
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:maxEms="integer"
android:width="integer"/>
Esto tendrá su ajuste de TextView en su contenido verticalmente, dependiendo de su valor de maxEms.
Tropecé con esto mientras buscaba una solución yo mismo. Había probado todas las otras soluciones que podía ver en el desbordamiento de pila, etc. pero ninguna funcionaba realmente, así que escribí la mía.
Básicamente al envolver la vista de texto en un diseño lineal personalizado, he podido medir el texto correctamente asegurándome de que se mide con un ancho fijo.
<!-- TextView wrapped in the custom LinearLayout that expects one child TextView -->
<!-- This view should specify the size you would want the text view to be displayed at -->
<com.custom.ResizeView
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_margin="10dp"
android:layout_weight="1"
android:orientation="horizontal" >
<TextView
android:id="@+id/CustomTextView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
</com.custom.ResizeView>
Luego, el código de diseño lineal
public class ResizeView extends LinearLayout {
public ResizeView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ResizeView(Context context) {
super(context);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
// oldWidth used as a fixed width when measuring the size of the text
// view at different font sizes
final int oldWidth = getMeasuredWidth() - getPaddingBottom() - getPaddingTop();
final int oldHeight = getMeasuredHeight() - getPaddingLeft() - getPaddingRight();
// Assume we only have one child and it is the text view to scale
TextView textView = (TextView) getChildAt(0);
// This is the maximum font size... we iterate down from this
// I''ve specified the sizes in pixels, but sp can be used, just modify
// the call to setTextSize
float size = getResources().getDimensionPixelSize(R.dimen.solutions_view_max_font_size);
for (int textViewHeight = Integer.MAX_VALUE; textViewHeight > oldHeight; size -= 0.1f) {
textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, size);
// measure the text views size using a fixed width and an
// unspecified height - the unspecified height means measure
// returns the textviews ideal height
textView.measure(MeasureSpec.makeMeasureSpec(oldWidth, MeasureSpec.EXACTLY), MeasureSpec.UNSPECIFIED);
textViewHeight = textView.getMeasuredHeight();
}
}
}
Espero que esto ayude a alguien.
Tuve el mismo problema y escribí una clase que parece funcionar para mí. Básicamente, utilicé un diseño estático para dibujar el texto en un lienzo por separado y volver a medir hasta que encuentre un tamaño de letra que se ajuste. Puedes ver la clase publicada en el tema a continuación. Espero que ayude.
Una forma sería especificar diferentes dimensiones sp para cada uno de los tamaños de pantalla generalizados. Por ejemplo, proporcione 8sp para pantallas pequeñas, 12sp para pantallas normales, 16 sp para grandes y 20 sp para xlarge. Entonces simplemente haga que sus diseños se refieran a @dimen text_size o lo que sea, y puede estar tranquilo, ya que la densidad se soluciona a través de la unidad sp. Consulte el siguiente enlace para obtener más información sobre este enfoque.
http://www.developer.android.com/guide/topics/resources/more-resources.html#Dimension
Debo señalar, sin embargo, que admitir más idiomas significa más trabajo durante la fase de prueba, especialmente si está interesado en mantener el texto en una línea, ya que algunos idiomas tienen palabras mucho más largas. En ese caso, cree un archivo dimens.xml en la carpeta values-de-large, por ejemplo, y modifique el valor manualmente. Espero que esto ayude.
tal vez intente configurar setHoriztonallyScrolling() en true antes de tomar medidas de texto para que textView no intente distribuir su texto en múltiples líneas
Nuevo desde Android O:
https://developer.android.com/preview/features/autosizing-textview.html
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:autoSizeTextType="uniform"
android:autoSizeMinTextSize="12sp"
android:autoSizeMaxTextSize="100sp"
android:autoSizeStepGranularity="2sp"
/>