Exemplo de TextInputLayout do Android

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:

  1. Habilitar/Desabilitar dicas flutuantes
  2. Habilitar/Desabilitar animação de dica flutuante
  3. Exibir mensagens de erro
  4. Mostrar contador de caracteres
  5. Alarmar o usuário quando a contagem de caracteres excede seu limite
  6. Personalizando a aparência do texto para dica flutuante, rótulo de erro, contador de caracteres
  7. 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