fundo
Muitas vezes, precisamos ajustar automaticamente a fonte do TextView aos limites dados a ele.
O problema
Infelizmente, embora existam muitos tópicos e postagens (e soluções sugeridas) falando sobre esse problema (exemplo aqui , aqui e aqui ), nenhum deles realmente funciona bem.
Por isso, decidi testar cada um deles até encontrar o negócio real.
Eu acho que os requisitos desse textView devem ser:
Deve permitir o uso de qualquer fonte, tipo de letra, estilo e conjunto de caracteres.
Deve lidar com largura e altura
Sem truncamento, a menos que o texto não possa caber devido à limitação que fornecemos (exemplo: texto muito longo, tamanho disponível muito pequeno). No entanto, poderíamos solicitar barra de rolagem horizontal / vertical, se desejarmos, apenas para esses casos.
Deve permitir várias linhas ou uma linha. No caso de várias linhas, permita linhas máxima e mínima.
Não deve ser lento no cálculo. Usando um loop para encontrar o melhor tamanho? Pelo menos, otimize-a e não aumente sua amostragem em 1 a cada vez.
No caso de várias linhas, deve-se preferir redimensionar ou usar mais linhas e / ou escolher as linhas usando o caractere "\ n".
O que eu tentei
Eu tentei tantas amostras (incluindo as dos links sobre os quais escrevi) e também tentei modificá-las para lidar com os casos de que já falei, mas nenhuma realmente funciona.
Fiz um projeto de amostra que me permite ver visualmente se o TextView se ajusta automaticamente.
Atualmente, meu projeto de amostra aleatoriamente apenas o texto (o alfabeto inglês mais dígitos) e o tamanho do textView, deixando-o com uma única linha, mas mesmo isso não funciona bem em nenhum dos exemplos que eu tentei.
Aqui está o código (também disponível aqui ):
Arquivo res/layout/activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent" tools:context=".MainActivity">
<Button android:id="@+id/button1" android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true" android:text="Button" />
<FrameLayout android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_above="@+id/button1"
android:layout_alignParentLeft="true" android:background="#ffff0000"
android:layout_alignParentRight="true" android:id="@+id/container"
android:layout_alignParentTop="true" />
</RelativeLayout>
Arquivo src/.../MainActivity.java
public class MainActivity extends Activity
{
private final Random _random =new Random();
private static final String ALLOWED_CHARACTERS ="qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890";
@Override
protected void onCreate(final Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final ViewGroup container=(ViewGroup)findViewById(R.id.container);
findViewById(R.id.button1).setOnClickListener(new OnClickListener()
{
@Override
public void onClick(final View v)
{
container.removeAllViews();
final int maxWidth=container.getWidth();
final int maxHeight=container.getHeight();
final FontFitTextView fontFitTextView=new FontFitTextView(MainActivity.this);
final int width=_random.nextInt(maxWidth)+1;
final int height=_random.nextInt(maxHeight)+1;
fontFitTextView.setLayoutParams(new LayoutParams(width,height));
fontFitTextView.setSingleLine();
fontFitTextView.setBackgroundColor(0xff00ff00);
final String text=getRandomText();
fontFitTextView.setText(text);
container.addView(fontFitTextView);
Log.d("DEBUG","width:"+width+" height:"+height+" text:"+text);
}
});
}
private String getRandomText()
{
final int textLength=_random.nextInt(20)+1;
final StringBuilder builder=new StringBuilder();
for(int i=0;i<textLength;++i)
builder.append(ALLOWED_CHARACTERS.charAt(_random.nextInt(ALLOWED_CHARACTERS.length())));
return builder.toString();
}
}
A questão
Alguém sabe de uma solução para esse problema comum que realmente funciona?
Mesmo uma solução com muito menos recursos do que eu escrevi, por exemplo, que possui apenas um número constante de linhas de texto e ajusta sua fonte de acordo com seu tamanho, mas nunca apresenta falhas estranhas e o texto fica muito grande / pequeno em comparação com o espaço disponível.
Projeto GitHub
Como esse é um TextView tão importante, decidi publicar uma biblioteca, para que todos pudessem usá-lo facilmente e contribuir com ele aqui .
fonte
Respostas:
Graças à correção simples do MartinH aqui , este código também cuida de
android:drawableLeft
,android:drawableRight
,android:drawableTop
eandroid:drawableBottom
tags.Minha resposta aqui deve fazer você feliz em Escalonar automaticamente o texto do TextView para caber dentro dos limites
Eu modifiquei seu caso de teste:
Estou postando código aqui, a pedido do desenvolvedor Android :
Efeito final:
Arquivo de layout de amostra:
E o código Java:
Aviso:
Cuidado com esse bug resolvido no Android 3.1 (Honeycomb).
fonte
Eu modifiquei um pouco a resposta do M-WaJeEh para levar em conta drawables compostos nas laterais.
Os
getCompoundPaddingXXXX()
métodos retornampadding of the view + drawable space
. Veja, por exemplo: TextView.getCompoundPaddingLeft ()Problema: isso corrige a medida da largura e altura do espaço do TextView disponível para o texto. Se não levarmos em consideração o tamanho do drawable, ele será ignorado e o texto acabará se sobrepondo ao drawable.
Segmento atualizado
adjustTextSize(String)
:fonte
Ok, eu usei a última semana para reescrever massivamente meu código para ajustar-se precisamente ao seu teste. Agora você pode copiar esse 1: 1 e ele funcionará imediatamente - inclusive
setSingleLine()
. Lembre-se de ajustarMIN_TEXT_SIZE
eMAX_TEXT_SIZE
se estiver buscando valores extremos.O algoritmo de convergência se parece com isso:
E toda a classe pode ser encontrada aqui.
O resultado é muito flexível agora. Isso funciona da mesma maneira declarada no xml:
... assim como construído programaticamente como em seu teste.
Eu realmente espero que você possa usar isso agora. Você pode ligar
setText(CharSequence text)
agora para usá-lo a propósito. A classe cuida de exceções estupendamente raras e deve ser sólida. A única coisa que o algoritmo ainda não suporta é:setMaxLines(x)
ondex >= 2
Mas eu adicionei extensos comentários para ajudá-lo a construir isso, se desejar!
Observe:
Se você apenas usar isso normalmente sem limitá-lo a uma única linha, poderá haver quebra de palavras, como você mencionou antes. Este é um recurso do Android , não é culpa do
AutoFitText
. O Android sempre quebra palavras muito longas para um TextView e é realmente uma conveniência. Se você quiser intervir aqui, consulte meus comentários e código começando na linha 203. Já escrevi uma divisão adequada e o reconhecimento para você, tudo o que você precisa fazer a partir de agora é dividir as palavras e modificá-las conforme desejar. .Em conclusão: você deve considerar reescrever seu teste para também suportar caracteres de espaço, assim:
Isso produzirá resultados muito bonitos (e mais realistas).
Você encontrará comentários para começar também neste assunto.
Boa sorte e cumprimentos
fonte
Minha exigência é
Consultei o link: Dimensionar automaticamente o texto do TextView para caber dentro dos limites (incluindo comentários) e também o DialogTitle.java
Descobri que a solução fornecida é agradável e simples, mas não altera dinamicamente o tamanho da caixa de texto. Funciona muito bem quando o tamanho do texto selecionado na exibição em lista é maior em tamanho que o comprimento do texto existente no
ScalableTextView
. Quando selecionado o texto com comprimento menor que o texto existente noScalableTextView
, ele não aumenta o tamanho do texto, mostrando o texto no tamanho menor.Modifiquei o ScalableTextView.java para reajustar o tamanho do texto com base no comprimento do texto. Aqui está o meu
ScalableTextView.java
Feliz codificação ....
fonte
Vou explicar como funciona esse atributo em versões mais baixas do Android, passo a passo:
1- Importe a biblioteca de suporte android 26.xx para o arquivo de classificação do projeto. Se não houver biblioteca de suporte no IDE, eles serão baixados automaticamente.
2- Abra seu arquivo XML de layout e refatorar como esta tag seu TextView. Este cenário é: quando o tamanho da fonte é aumentado no sistema, ajuste o texto à largura disponível, não a quebra de linha.
fonte
Aviso, bug no Android 3 (Honeycomb) e Android 4.0 (Ice Cream Sandwich)
Versões do Android: 3.1 - 4.04 têm um bug, que setTextSize () dentro do TextView funciona apenas pela primeira vez (primeira chamada).
O bug é descrito no problema 22493: erro de altura do TextView no Android 4.0 e no problema 17343: a altura e o texto do botão não retornam ao seu estado original após aumentar e diminuir o tamanho do texto no HoneyComb .
A solução alternativa é adicionar um caractere de nova linha ao texto atribuído ao TextView antes de alterar o tamanho:
Eu o uso no meu código da seguinte maneira:
Eu adiciono esse caractere "\ u3000" nas partes esquerda e direita do meu texto, para mantê-lo centralizado. Se você o alinhar à esquerda, anexe apenas à direita. Claro que também pode ser incorporado ao widget AutoResizeTextView, mas eu queria manter o código de correção fora.
fonte
Agora existe uma solução oficial para esse problema. O dimensionamento automático de TextViews introduzidas no Android O está disponível na Biblioteca de suporte 26 e é compatível com versões anteriores até o Android 4.0.
https://developer.android.com/preview/features/autosizing-textview.html
Não sei por que o https://stackoverflow.com/a/42940171/47680, que também inclui essas informações, foi excluído por um administrador.
fonte
A partir de junho de 2018, o Android suporta oficialmente esse recurso para Android 4.0 (API nível 14) e superior.
Com o Android 8.0 (nível API 26) e superior:
Versões do Android anteriores ao Android 8.0 (nível 26 da API):
Confira minha resposta detalhada .
fonte
Converta a exibição de texto em uma imagem e dimensione a imagem dentro dos limites.
Aqui está um exemplo de como converter uma exibição em uma imagem: convertendo uma exibição em bitmap sem exibi-la no Android?
O problema é que seu texto não será selecionável, mas deve funcionar. Eu não tentei, então não tenho certeza de como ficaria (por causa do dimensionamento).
fonte
Abaixo está o avalancha TextView com funcionalidade adicional para a fonte personalizada.
Uso:
Não se esqueça de adicionar: xmlns: foo = "http://schemas.android.com/apk/res-auto". A fonte deve estar no diretório de ativos
bugs conhecidos: não funciona com o Android 4.03 - as fontes são invisíveis ou muito pequenas (a avalancha original também não funciona) abaixo é uma solução alternativa para esse bug: https://stackoverflow.com/a/21851239/2075875
fonte
Tente isto
fonte
Se você está procurando algo mais fácil:
fonte
Solução rápida para o problema descrito por @Malachiasz
Corrigi o problema adicionando suporte personalizado para isso na classe de redimensionamento automático:
Basta ligar em
yourView.setTextCompat(newTextValue)
vez deyourView.setText(newTextValue)
fonte
Tente adicionar
LayoutParams
eMaxWidth
eMaxHeight
aoTextView
. Isso forçará o layout a respeitar o contêiner pai e não estourar.fonte
Desde o Android O, é possível redimensionar automaticamente o texto em xml:
https://developer.android.com/preview/features/autosizing-textview.html
fonte
Depois de experimentar o Autosizing TextView oficial do Android , descobri que se a sua versão do Android é anterior ao Android 8.0 (API nível 26), é necessário usá-lo
android.support.v7.widget.AppCompatTextView
e verifique se a versão da biblioteca de suporte está acima de 26.0.0. Exemplo:update :
De acordo com a resposta do @ android-developer, verifiquei o
AppCompatActivity
código-fonte e encontrei essas duas linhas emonCreate
final AppCompatDelegate delegate = getDelegate(); delegate.installViewFactory();
e em
AppCompatDelegateImpl
'screateView
ele usa a
AppCompatViewInflater
visualizaçãoAppCompatViewInflater
inflada ; quando createView, ele usa AppCompatTextView para "TextView".No meu projeto eu não uso
AppCompatActivity
, então eu preciso usar<android.support.v7.widget.AppCompatTextView>
em xml.fonte
AppCompatActivity
. AppCompatActivity usa o layout do inflador AppCompatViewInflater.