Neste tutorial, vamos examinar em detalhes as funcionalidades que o TextInputLayout do Android nos fornece. O TextInputLayout do Android é um componente de design que faz parte da Biblioteca de Suporte Material Design.
TextInputLayout do Android
O TextInputLayout do Android estende o LinearLayout. O uso principal de um TextInputLayout é atuar como um invólucro para EditText (ou seus descendentes) e permitir animações de dica flutuante. Regra básica: O TextInputLayout deve envolver TextInputEditText em vez do EditText normal. Motivo? O TextInputEditText é uma subclasse de EditText e é projetado para ser usado como um filho do TextInputLayout. Além disso, usar um EditText resultaria em um aviso: EditText adicionado não é um TextInputEditText. Use essa classe em vez disso
. O TextInputLayout tem muito mais a oferecer do que apenas exibir rótulos de dica flutuante.
Recursos do TextInputLayout do Android
Alguns dos recursos que abordaremos neste tutorial são:
- Habilitar/Desabilitar dicas flutuantes
- Habilitar/Desabilitar animação de dica flutuante
- Exibir mensagens de erro
- Mostrar contador de caracteres
- Alarmar o usuário quando a contagem de caracteres excede seu limite
- Personalizando a aparência do texto para dica flutuante, rótulo de erro, contador de caracteres
- Alternar visibilidade de senha
Vamos analisar cada uma dessas funcionalidades e implementá-las em um projeto do Android Studio.
Estrutura do projeto de exemplo do Android TextInputLayout
Este é um aplicativo de uma única atividade. Faremos tudo dentro do layout, atividade e arquivos
styles.xml
e colors.xml
. Primeiramente, adicione a dependência para a biblioteca de suporte de design dentro do arquivo build.gradle
conforme mostrado abaixo.
compile 'com.android.support:design:25.3.1'
Habilitando/Desabilitando dicas flutuantes
Dicas flutuantes estão habilitadas por padrão em um TextInputLayout. Para desabilitá-las, precisamos adicionar o seguinte atributo dentro da tag: app:hintEnabled="false"
. O código XML abaixo é do layout activity_main.xml
e possui três campos EditText.
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="https://schemas.android.com/apk/res/android"
xmlns:app="https://schemas.android.com/apk/res-auto"
xmlns:tools="https://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:context="com.journaldev.featuresoftextinputlayout.MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<android.support.design.widget.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="@dimen/activity_horizontal_margin"
android:hint="TextInputEditText" />
<android.support.design.widget.TextInputLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="@dimen/activity_horizontal_margin">
<android.support.design.widget.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Floating Hint Enabled Default" />
</android.support.design.widget.TextInputLayout>
<android.support.design.widget.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="@dimen/activity_horizontal_margin"
app:hintEnabled="false">
<android.support.design.widget.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Floating Hint Disabled" />
</android.support.design.widget.TextInputLayout>
</LinearLayout>
</ScrollView>
O terceiro campo EditText tem a dica flutuante desativada. Vamos ver a saída que o código acima nos dá:
Habilitando/Desabilitando a animação da dica flutuante
Similar ao recurso anterior, a animação da dica flutuante está habilitada por padrão. Para desabilitá-la, precisamos adicionar o seguinte atributo dentro da tag TextInputLayout. app:hintAnimationEnabled="false"
O código XML abaixo é do layout activity_main.xml
e possui campos EditText para cada um dos casos.
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="https://schemas.android.com/apk/res/android"
xmlns:app="https://schemas.android.com/apk/res-auto"
xmlns:tools="https://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:context="com.journaldev.featuresoftextinputlayout.MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<android.support.design.widget.TextInputLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="@dimen/activity_horizontal_margin">
<android.support.design.widget.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Floating Hint Enabled Default" />
</android.support.design.widget.TextInputLayout>
<android.support.design.widget.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="@dimen/activity_horizontal_margin"
app:hintAnimationEnabled="false">
<android.support.design.widget.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Hint Animation Disabled" />
</android.support.design.widget.TextInputLayout>
</LinearLayout>
</ScrollView>
A saída do código acima é mostrada abaixo. Vale ressaltar que o segundo campo EditText não anima a dica flutuante quando está em foco.
Estilizando o TextAppearance da dica
Para usar uma textColor
e textSize
personalizadas para as dicas, é usado o seguinte atributo: app:hintTextAppearance="@style/HintText"
O estilo HintText é escrito dentro do arquivo styles.xml
como mostrado abaixo
<style name="HintText" parent="TextAppearance.Design.Hint">
<item name="android:textSize">16sp</item>
<item name="android:textColor">@color/colorPrimary</item>
</style>
O código XML abaixo é do layout activity_main.xml
e possui campos de texto EditText para ambos os casos (com/sem hintTextAppearance).
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="https://schemas.android.com/apk/res/android"
xmlns:app="https://schemas.android.com/apk/res-auto"
xmlns:tools="https://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:context="com.journaldev.featuresoftextinputlayout.MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<android.support.design.widget.TextInputLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="@dimen/activity_horizontal_margin">
<android.support.design.widget.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Floating Hint Enabled" />
</android.support.design.widget.TextInputLayout>
<android.support.design.widget.TextInputLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="@dimen/activity_horizontal_margin"
app:hintTextAppearance="@style/HintText">
<android.support.design.widget.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Custom Hint TextAppearance" />
</android.support.design.widget.TextInputLayout>
</LinearLayout>
</ScrollView>
O resultado do código acima é mostrado abaixo.
Contador de caracteres
O Contador de caracteres é um recurso usado por muitos aplicativos. (Lembra do limite de caracteres do Twitter?). Defina app:counterEnabled
como true e app:counterMaxLength
com o número máximo de caracteres que você deseja no TextInputLayout. O Contador de caracteres é exibido abaixo do EditText por padrão (canto inferior direito) e, ao escrever este tutorial, não há maneira de alterar a posição ainda. Estilizar o contador é semelhante à estilização do texto da dica. app:counterTextAppearance
é o atributo usado desta vez. Adicionamos o seguinte estilo no arquivo styles.xml em nosso projeto.
<style name="CounterText" parent="TextAppearance.Design.Counter">
<item name="android:textSize">16sp</item>
<item name="android:textColor">@color/my_pink</item>
</style>
O código XML abaixo é do layout activity_main.xml
e possui campos de texto EditText com um contador de caracteres padrão e um personalizado.
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="https://schemas.android.com/apk/res/android"
xmlns:app="https://schemas.android.com/apk/res-auto"
xmlns:tools="https://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:context="com.journaldev.featuresoftextinputlayout.MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<android.support.design.widget.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="@dimen/activity_horizontal_margin"
app:counterEnabled="true"
app:counterMaxLength="5"
app:hintTextAppearance="@style/HintText">
<android.support.design.widget.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Character Counter Limit 10" />
</android.support.design.widget.TextInputLayout>
<android.support.design.widget.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="@dimen/activity_horizontal_margin"
app:counterEnabled="true"
app:counterMaxLength="5"
app:counterTextAppearance="@style/CounterText"
app:hintTextAppearance="@style/HintText">
<android.support.design.widget.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Character Counter Custom TextAppearance" />
</android.support.design.widget.TextInputLayout>
</LinearLayout>
</ScrollView>
A saída do código acima é mostrada abaixo. Vamos observar atentamente a saída acima.
- O primeiro campo EditText altera a cor do contador textColor, a cor da dica textColor e a cor do indicador quando o número de caracteres excede o limite.
- O segundo campo EditText faz o mesmo, mas também altera o contador custom textColor e o tamanho do texto personalizado quando o limite é excedido.
Para especificar o estilo que precisamos quando o contador de caracteres excede o limite, precisamos usar o atributo counterFlow que veremos a seguir.
Estouro do Contador de Caracteres
Como vimos acima, quando o número de caracteres excede o limite definido, o texto do contador usa os atributos definidos em counterFlow. Se os atributos não estiverem presentes, ele manterá os padrões como vimos na saída acima. Precisamos usar o seguinte parâmetro app:counterOverflowTextAppearance
. O estilo para CounterOverflow
está presente dentro do arquivo styles.xml:
<style name="CounterOverFlow" parent="TextAppearance.Design.Counter.Overflow">
<item name="android:textSize">16sp</item>
<item name="android:textColor">@color/my_orange</item>
</style>
Adicione o trecho de código abaixo ao layout anterior activity_main.xml
:
<android.support.design.widget.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="@dimen/activity_horizontal_margin"
app:counterEnabled="true"
app:counterMaxLength="5"
app:counterOverflowTextAppearance="@style/CounterOverFlow"
app:counterTextAppearance="@style/CounterText"
app:hintTextAppearance="@style/HintText">
<android.support.design.widget.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="CounterOverflow CustomTextAppearance" />
</android.support.design.widget.TextInputLayout>
Vamos executar o aplicativo novamente.
Etiqueta de Erro
Definir app:errorEnabled
como true nos permite exibir um texto de erro em condição abaixo do nosso campo EditText. Para estilizar o texto de erro, usamos o atributo app:errorTextAppearance
e adicionamos o seguinte código dentro do nosso arquivo styles.xml
.
<style name="ErrorText" parent="TextAppearance.Design.Error">
<item name="android:textSize">16sp</item>
<item name="android:textColor">@color/my_black</item>
</style>
O código XML abaixo é do layout activity_main.xml
e possui campos EditText para uma etiqueta de erro padrão e uma personalizada.
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="https://schemas.android.com/apk/res/android"
xmlns:app="https://schemas.android.com/apk/res-auto"
xmlns:tools="https://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:context="com.journaldev.featuresoftextinputlayout.MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<android.support.design.widget.TextInputLayout
android:id="@+id/errorInputLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="@dimen/activity_horizontal_margin"
app:counterEnabled="true"
app:counterMaxLength="5"
app:counterOverflowTextAppearance="@style/CounterOverFlow"
app:counterTextAppearance="@style/CounterText"
app:errorEnabled="true"
app:hintTextAppearance="@style/HintText">
<android.support.design.widget.TextInputEditText
android:id="@+id/errorEditText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Default Error Label" />
</android.support.design.widget.TextInputLayout>
<android.support.design.widget.TextInputLayout
android:id="@+id/customErrorInputLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="@dimen/activity_horizontal_margin"
app:counterEnabled="true"
app:counterMaxLength="5"
app:counterOverflowTextAppearance="@style/CounterOverFlow"
app:counterTextAppearance="@style/CounterText"
app:errorEnabled="true"
app:errorTextAppearance="@style/ErrorText"
app:hintTextAppearance="@style/HintText">
<android.support.design.widget.TextInputEditText
android:id="@+id/customErrorEditText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Custom Error Label" />
</android.support.design.widget.TextInputLayout>
</LinearLayout>
</ScrollView>
Para exibir o texto de erro, precisamos chamar o método setError(String)
em uma instância de TextInputLayout em nossa classe MainActivity.java
, conforme mostrado abaixo.
package com.journaldev.featuresoftextinputlayout;
import android.support.design.widget.TextInputEditText;
import android.support.design.widget.TextInputLayout;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
public class MainActivity extends AppCompatActivity {
TextInputLayout errorInputLayout, customErrorInputLayout;
TextInputEditText errorEditText, customErrorEditText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
errorEditText = (TextInputEditText) findViewById(R.id.errorEditText);
errorInputLayout = (TextInputLayout) findViewById(R.id.errorInputLayout);
customErrorEditText = (TextInputEditText) findViewById(R.id.customErrorEditText);
customErrorInputLayout = (TextInputLayout) findViewById(R.id.customErrorInputLayout);
errorEditText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
if (s.length() > errorInputLayout.getCounterMaxLength())
errorInputLayout.setError("Max character length is " + errorInputLayout.getCounterMaxLength());
else
errorInputLayout.setError(null);
}
});
customErrorEditText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
if (s.length() > customErrorInputLayout.getCounterMaxLength())
customErrorInputLayout.setError("Max character length is " + customErrorInputLayout.getCounterMaxLength());
else
customErrorInputLayout.setError(null);
}
});
}
}
No código acima, adicionamos um TextChangedListener
(que implementa TextWatcher) em cada instância de TextInputEditText. Exibimos o rótulo de erro quando a contagem de caracteres atual excede o limite máximo do contador. Para limpar o rótulo de erro, definimos o valor dentro de setError()
como null. A saída que o código acima nos dá é: Nota: O indicador do campo de texto usa a mesma cor que o rótulo de erro. Ele substitui a cor definida por counterOverflow, portanto tem a maior prioridade.
Alternar Visibilidade de Senha
Definir app:passwordToggleEnabled
como true permite mostrar/ocultar a senha. Para alterar a cor do ícone, use app:passwordToggleTint
. O código XML abaixo é do layout activity_main.xml
e possui campos EditText para um alternador de visibilidade de senha (ícone padrão e com uma tonalidade).
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="https://schemas.android.com/apk/res/android"
xmlns:app="https://schemas.android.com/apk/res-auto"
xmlns:tools="https://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:context="com.journaldev.featuresoftextinputlayout.MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<android.support.design.widget.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="@dimen/activity_horizontal_margin"
app:counterEnabled="true"
app:counterMaxLength="5"
app:counterOverflowTextAppearance="@style/CounterOverFlow"
app:counterTextAppearance="@style/CounterText"
app:hintTextAppearance="@style/HintText"
app:passwordToggleEnabled="true">
<android.support.design.widget.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Password Visibility Toggle"
android:inputType="textPassword" />
</android.support.design.widget.TextInputLayout>
<android.support.design.widget.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="@dimen/activity_horizontal_margin"
app:counterEnabled="true"
app:counterMaxLength="5"
app:counterOverflowTextAppearance="@style/CounterOverFlow"
app:counterTextAppearance="@style/CounterText"
app:hintTextAppearance="@style/HintText"
app:passwordToggleEnabled="true"
app:passwordToggleTint="@color/my_orange">
<android.support.design.widget.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Password Visibility Toggle Tint"
android:inputType="textPassword" />
</android.support.design.widget.TextInputLayout>
</LinearLayout>
</ScrollView>
A saída exibida pelo código acima é: Nota: Podemos usar nossos próprios ícones personalizados para alternar a visibilidade da senha usando
app:passwordToggleDrawable
. Isso conclui este tutorial. Cobrimos todos os principais recursos presentes no TextInputLayout. Você pode baixar o Projeto de Exemplo Android TextInputLayout no link abaixo. Ele inclui cada um dos trechos de código acima.
Baixar Projeto Android TextInputLayout
Referência: Documentação Oficial do Android
Source:
https://www.digitalocean.com/community/tutorials/android-textinputlayout-example