TextView.setTextSize se comporta de maneira anormal - como definir o tamanho do texto de textview dinamicamente para telas diferentes

119

A chamada TextView.setTextSize()está funcionando de maneira anormal. Logo após a chamada para setTextSizese obtivermos um, getTextSizeela retornará um valor muito mais alto do que o definimos anteriormente.

Aqui está o que estamos fazendo:

zoomControl.setOnZoomInClickListener(new OnClickListener() {
    public void onClick(View view) {
        float size = mViewShabad.getTextSize() + 1;
        textView.setTextSize(size);
    }
});

Alguém viu isso antes?

singhspk
fonte
2
Você está obtendo e definindo o tamanho do texto em dois objetos diferentes?
Cheryl Simon

Respostas:

359

A diferença aqui é que no setTextSize(int size)método, o tipo de unidade por padrão é "sp" ou "pixels dimensionados". Este valor será uma dimensão de pixel diferente para cada densidade de tela (ldpi, mdpi, hdpi).

getTextSize(), por outro lado, retorna as dimensões reais em pixels do texto.

Você pode usar setTextSize(int unit, float size)para especificar um tipo de unidade. Os valores constantes para isso podem ser encontrados na classe TypedValue, mas alguns deles são:

TypedValue.COMPLEX_UNIT_PX   //Pixels

TypedValue.COMPLEX_UNIT_SP   //Scaled Pixels

TypedValue.COMPLEX_UNIT_DIP  //Device Independent Pixels
Kevin Coppock
fonte
Acabei de descobrir isso e estava prestes a postar aqui. Muito obrigado!
singhspk
1
Acho que deveria ser por TypedValue (singular). A importação é android.util.TypedValue;
Hein du Plessis,
5
Além disso, ele só começou a fazer isso na API de nível 7. Outro "pegadinha" em uma API ridícula.
mxcl de
3
Importante observar a ordem do argumento - eu acidentalmente setTextSize (size, TypedValue.COMPLEX_UNIT_SP) porque essa foi a ordem que presumi por engano!
Mark
1
Curiosamente, no ICS do meu Galaxy Nexus, usar setTextSize (14, TypedValue.COMPLEX_UNIT_SP) não fez efeito (usei o tamanho padrão), mas quando atualizei para o Jelly Bean, nenhum texto foi exibido (como o tamanho 0). Eu estava prestes a relatar um bug do Jelly Bean quando percebi meu erro!
Mark
20

esse problema aconteceu porque o getTextSize()método retorna o tamanho em pixels que depende da densidade da tela! para obter o tamanho real do texto, use:

DisplayMetrics metrics;
metrics = getApplicationContext().getResources().getDisplayMetrics();
float Textsize =myTextView.getTextSize()/metrics.density;
myTextView.setTextSize(Textsize+1);

Espero que resolva :)

M_AWADI
fonte
2
Resolvi meu problema usando métricas de exibição com setTextSize(int unit, float size)
Edward Chiang
8

se definir alterar o tamanho da fonte, algo causa erro de exibição, você pode fazer o seguinte:

setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15.f);
hui 谁 与 争辉
fonte
3
Quem define textSize em DIP?
IgorGanapolsky
4

Quando tentamos definir o problema de setText () programaticamente com getTextSize (), retorna o valor em px em vez de sp / dp / dip e sabemos 1sp / dp = 1.5px (tamanho da tela = 240).

 titleBar.setTextSize(TypedValue.COMPLEX_UNIT_SP, (getResources().getDimension(R.dimen.text_size)*1.5f)); 

está funcionando perfeitamente para mim ou podemos usar displaymatrix para proporção px: sp / dp e, em seguida, substituir esse valor por 1.5f

means-> titleBar.setTextSize(TypedValue.COMPLEX_UNIT_SP, (getResources().getDimension(R.dimen.text_size)*your_sp_and_px_ratio_in_int f));
Ranjan
fonte
3

Depois de muito tempo acertou isso e finalmente resolveu assim

textView.setTextSize(TypedValue.COMPLEX_UNIT_PX,
          getResources().getDimension(R.dimen.textsize));

crie uma pasta dimen como este res / valores / dimensões.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>

 <dimen name="textsize">8sp</dimen>

 </resources>
NagarjunaReddy
fonte
2

Em suma, se você quiser diminuir o tamanho do seu texto

float size = mViewShabad.getTextSize()*1.1f;
textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, size);

Como getTextSize () retorna UNIT_PX, então devemos usar UNIT_PX

Frank Nguyen
fonte
1

Solução Kotlin

Para configurar usando um recurso, basta usar este:

textView.setTextSize(COMPLEX_UNIT_PX, textView.resources.getDimension(R.dimen.my_text_size))

Para fazer o mesmo com um valor de recurso, adicione esta propriedade de extensão para definir muito mais facilmente o tamanho do seu texto

textView.textSizeRes = R.dimen.my_text_size

var TextView.textSizeRes
    get() = textSize.toInt()
    set(@DimenRes textSizeRes) {
        setTextSize(COMPLEX_UNIT_PX, resources.getDimension(textSizeRes))
    }
Gibolt
fonte
0

Adicionando algum sabor extra para esta resposta, pois também gerou um pouco de confusão. Você deve ser capaz de inserir este teste em qualquer @RunWith(AndroidJUnit4.class)teste que tenha em seu projeto (você também precisará adicionar a dimensão ao seu dimens.xml).

Observação: todos esses testes passam

@Test public void testScaledFontSizes() {
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
    final Context context = InstrumentationRegistry.getTargetContext();

    Configuration configuration = context.getResources().getConfiguration();
    configuration.fontScale = 2.0f;
    configuration.densityDpi = 160; // mdpi, 1:1
    context.getResources().updateConfiguration(configuration, null);

    float scaledTextSize = context.getResources().getDimensionPixelSize(R.dimen.sp_15);
    assertEquals(30.0f, scaledTextSize);

    // Create a new TextView with the explicitly set configuration
    TextView textView = new TextView(context);
    textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, scaledTextSize);

    // 30, because font size is scaled
    assertEquals(30.0f, textView.getTextSize());

    // This is what we *don't* want, it's scaled *twice*!
    textView.setTextSize(scaledTextSize);
    assertEquals(60.0f, textView.getTextSize());

    // DP instead of SP tests
    float fifteenDp = context.getResources().getDimensionPixelSize(R.dimen.dp_15);
    assertEquals(15.0f, fifteenDp);

    textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, fifteenDp);
    // Still 15, because it's DP, not SP
    assertEquals(15.0f, fifteenDp);

    textView.setTextSize(fifteenDp);
    // 30, because setTextSize DOES font scaling
    assertEquals(30.0f, textView.getTextSize());
  }
}

A grande lição que descobri é que TextView.setTextSize(float) aplica o dimensionamento da fonte , então se você passar em um dimen que já está rotulado como SP em vez de DP, então ele receberá o dimensionamento da fonte duas vezes .

Kevin Grant
fonte