Como escalar / redimensionar o texto para caber um TextView ?

? RyanM @ | Original: StackOverFlow
---

Eu estou tentando criar um método para redimensionar o texto multi- linha em um TextView de tal forma que ele se encaixa dentro dos limites (tanto as dimensões X e Y) do TextView .

No momento, eu tenho alguma coisa, mas tudo que faz é redimensionar o texto de tal forma que apenas a primeira letra / personagem do texto preenche as dimensões do TextView (ou seja, somente a primeira letra é visível, e é enorme ) . Eu preciso dele para caber todas as linhas do texto dentro dos limites da TextView .

Aqui está o que eu tenho até agora :

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

Acho que o problema está no uso de tv.getPaint().getTextBounds(...) . Ele sempre retorna pequenos números para os limites de texto ... pequeno em relação aos tv.getWidth() e tv.getHeight() valores ... mesmo se o tamanho do texto é muito maior do que a largura ou a altura da TextView .

---

Top 5 Responder

1snctln @

talvez tente definir http://developer.android.com/reference/android/widget/TextView.html#setHorizontallyScrolling%28boolean%29 a verdade antes de tomar medidas de texto para que o textView não tenta layout de seu texto em várias linhas

2RyanM @

Eu era capaz de responder à minha própria pergunta usando o seguinte código (veja abaixo), mas a minha solução era muito específico para a aplicação. Por exemplo, este, provavelmente, só uma boa aparência e / ou trabalhar para uma TextView dimensionada para aprox. 1/2 da tela ( com também um 40px 20px margem superior e laterais margens ... sem margem inferior ) .

A utilização desta abordagem, porém, você pode criar sua própria implementação similar. O método estático, basicamente, apenas olha para o número de caracteres e determina um fator de escala a aplicar-se o tamanho do texto do TextView, e, em seguida, de forma incremental aumenta o tamanho do texto até a altura total ( uma altura estimada - usando a largura do texto, o texto altura e a largura da TextView ) está abaixo daquela do TextView . Os parâmetros necessários para determinar o fator de escala ( ou seja, o if / else if ) foram definidos por e - check- palpite . Você provavelmente vai ter que brincar com os números para fazer o trabalho para sua aplicação em particular .

Esta não é a solução mais elegante, embora fosse fácil de código e ele funciona para mim. Alguém tem uma abordagem melhor?

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 a sua única exigência é ter o texto dividida automaticamente e continuar na próxima linha e a altura não é importante, então, apenas tê-lo como este.

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

Isto terá seu envoltório TextView a ele é o conteúdo verticalmente dependendo do seu valor maxEms .

4vsm @

Verifique se a minha solução ajuda a:

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

5Chase @

Eu tive o mesmo problema e escreveu uma classe que parece funcionar para mim. Basicamente, eu usei um layout estático para desenhar o texto em uma tela separada e volte a medir até que eu encontre um tamanho de letra que se encaixa. Você pode ver a classe postadas no tópico abaixo. Espero que ajude.

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