Exemplo de TextInputLayout do Android

Neste tutorial, estaremos analisando detalhadamente os recursos que o Android TextInputLayout nos proporciona. O Android TextInputLayout é um componente de design que faz parte da Material Design Support Library.

Android TextInputLayout

Android TexInputLayout estende LinearLayout. O uso principal de um TextInputLayout é atuar como um invólucro para EditText (ou seu descendente) e permitir animações de dica flutuante. Regra geral: TextInputLayout deve envolver TextInputEditText em vez do normal EditText. Motivo? TextInputEditText é uma subclasse de EditText e é projetado para ser usado como filho do TextInputLayout. Além disso, usar EditText em vez disso nos daria um aviso: EditText adicionado não é um TextInputEditText. Por favor, mude para usar essa classe. TextInputLayout oferece muito mais do que apenas exibir rótulos de dica flutuante.

Recursos do Android TextInputLayout

Alguns dos recursos que abordaremos neste tutorial são:

  1. Ativar/Desativar dicas flutuantes
  2. Ativar/Desativar animação de dica flutuante
  3. Exibir mensagens de erro
  4. Mostrar contador de caracteres
  5. Alarmar o usuário quando o Limite de Caracteres Excede
  6. Personalizando a Aparência do Texto para dica flutuante, rótulo de erro, contador de caracteres
  7. Alternar Visibilidade da Senha

Vamos analisar cada um desses recursos e implementá-los em um Projeto Android Studio.

Estrutura do Projeto de Exemplo Android TextInputLayout

Este é um aplicativo de única atividade. Faremos tudo dentro do layout, atividade e arquivos styles.xml e colors.xml. Primeiro, adicione a dependência para a biblioteca de suporte de design dentro do arquivo build.gradle como mostrado abaixo.

compile 'com.android.support:design:25.3.1'

Habilitando/Desabilitando Dicas Flutuantes

As 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 Animação da Dica Flutuante

Similar à funcionalidade anterior, a animação da dica flutuante está habilitada por padrão. Para desativá-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 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. É digno de nota mencionar que o segundo campo EditText não anima a dica flutuante quando focado.

Estilizando o Texto da Dica TextAppearance

Para usar um textColor personalizado e textSize 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 EditText para cada um dos 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>

A saída do código acima é mostrada abaixo.

Contador de Caracteres

O Contador de Caracteres é um recurso usado por várias aplicações. (Lembra do limite de caracteres do Twitter?). Defina app:counterEnabled como true e app:counterMaxLength com o número máximo de caracteres desejados no TextInputLayout. O Contador de Caracteres é exibido abaixo do EditText por padrão (canto inferior direito) e, ao escrever este tutorial, ainda não há maneira de mudar a posição. Estilizar o contador é semelhante à estilização do texto da dica. app:counterTextAppearance é o atributo usado desta vez. Adicionamos o seguinte estilo dentro do 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 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 é dada abaixo. Vamos observar de perto a saída acima.

  • O primeiro campo EditText muda sua cor de texto do contador, cor do texto de dica e a cor do indicador quando o número de caracteres é excedido.
  • O segundo campo EditText faz o mesmo, mas também muda a cor de texto do contador personalizado e o tamanho de texto personalizado quando o limite é excedido.

Para especificar o estilo que precisamos quando o contador de caracteres excede seu limite, precisamos usar o atributo counterFlow que veremos a seguir.

Overflow 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 permanecerá com 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 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.

Rótulo de Erro

Configurar app:errorEnabled para true nos permite exibir um texto de erro sob condição abaixo do nosso campo EditText. Para estilizar o Texto de Erro, usaríamos o atributo app:errorTextAppearance e adicionar 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 um rótulo de erro 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: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, teremos que 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 da Senha

Configurar `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 encerra este tutorial. Cobrimos todos os principais recursos presentes no TextInputLayout. Você pode baixar o Projeto de Exemplo Android TextInputLayout pelo 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