Come scalare / ridimensionare il testo per adattarsi a un TextView ?

? RyanM @ | Original: StackOverFlow

Sto cercando di creare un metodo per il ridimensionamento del testo multilinea in un TextView in modo tale che si adatta entro i limiti (sia le dimensioni X e Y ) della TextView .

Al momento, ho qualcosa, ma tutto ciò che fa è ridimensionare il testo in modo che solo la prima lettera / carattere del testo riempie le dimensioni della TextView ( cioè solo la prima lettera è visibile, ed è enorme ) . Ho bisogno di adattarsi tutte le righe del testo entro i limiti del TextView .

Ecco quello che ho finora :

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

Penso che il problema è l'uso di tv.getPaint().getTextBounds(...) . Restituisce sempre piccoli numeri per il limite di testo ... piccolo rispetto ai valori tv.getWidth() e tv.getHeight() ... anche se la dimensione del testo è di gran lunga maggiore della larghezza o l'altezza della TextView .

Top 5 Risposta

1snctln @

magari provare a impostare http://developer.android.com/reference/android/widget/TextView.html#setHorizontallyScrolling%28boolean%29 true prima di eseguire misurazioni di testo in modo che il TextView non cerca di impaginare il testo su più righe

2RyanM @

Sono stato in grado di rispondere alla mia domanda utilizzando il seguente codice ( vedi sotto ), ma la mia soluzione era molto specifico per l'applicazione . Ad esempio, questo sarà probabilmente solo guardare bene e / o lavorare per un TextView dimensionato per circa . 1/2 dello schermo ( con anche un 40px 20px margine superiore e laterali margini ... no margine inferiore ) .

L' utilizzo di questo metodo, però, è possibile creare una propria implementazione simile . Il metodo statico essenzialmente si limita il numero di caratteri e determina un fattore di scala da applicare al formato testo del TextView, e poi aumenta gradualmente la dimensione del testo fino all'altezza complessiva ( un'altezza stimata - utilizzando la larghezza del testo, testo altezza e la larghezza della TextView ) è appena inferiore a quello del TextView . I parametri necessari per determinare il fattore di scala ( cioè il if / else if ) sono stati fissati da indovinare - e -check . È probabile che sia per giocare con i numeri per farlo funzionare per una particolare applicazione .

Questa non è la soluzione più elegante, anche se era facile da codice e funziona per me . Qualcuno ha un approccio migliore ?

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

Thanks.

3Octavian Damiean @

Se il vostro unico requisito è quello di avere il testo automaticamente diviso e continua nella riga successiva e l'altezza non è importante, allora semplicemente in questo modo .

<TextView
    android:layout_height="wrap_content"
    android:layout_width="wrap_content"
    android:maxEms="integer"
    android:width="integer"/>

Questo avrà il vostro impacco TextView ad esso è contenuto in verticale a seconda del valore maxEms .

4vsm @

Controllare se la mia soluzione consente di:

http://stackoverflow.com/questions/5033012/auto-scale-textview-text-to-fit-within-bounds/5280436#5280436

5Chase @

Ho avuto lo stesso problema e ho scritto una classe che sembra funzionare per me . Fondamentalmente, ho usato un layout statico per disegnare il testo in una tela separato e rimisurare fino a trovare una dimensione di carattere che si adatta . Si può vedere la classe ha pubblicato un argomento di seguito . Spero che aiuta .

http://stackoverflow.com/questions/5033012/auto-scale-textview-text-to-fit-within-bounds/5535672#5535672