Ejemplo de TextInputLayout de Android

En este tutorial, vamos a profundizar en las características que nos proporciona Android TextInputLayout. Android TextInputLayout es un componente de diseño que viene con la Biblioteca de Soporte de Material Design.

Android TextInputLayout

Android TextInputLayout extiende LinearLayout. El uso principal de un TextInputLayout es actuar como un contenedor para EditText (o sus descendientes) y habilitar animaciones de indicaciones flotantes. Regla general: TextInputLayout debería envolver a TextInputEditText en lugar del EditText normal. ¿La razón? TextInputEditText es una subclase de EditText y está diseñada para ser utilizada como hijo de TextInputLayout. Además, usar un EditText en su lugar nos mostraría una advertencia: Se ha añadido un EditText que no es un TextInputEditText. Por favor, cambie y utilice esa clase en su lugar. TextInputLayout ofrece mucho más que simplemente mostrar etiquetas de indicación flotantes.

Características de Android TextInputLayout

Algunas de las características que cubriremos en este tutorial son:

  1. Habilitar/Deshabilitar indicaciones flotantes
  2. Habilitar/Deshabilitar animación de indicaciones flotantes
  3. Mostrar mensajes de error
  4. Mostrar contador de caracteres
  5. Alarmar al usuario cuando el recuento de caracteres excede su límite
  6. Personalización de la apariencia del texto para sugerencias flotantes, etiquetas de error, contador de caracteres
  7. Alternar la visibilidad de la contraseña

Examinaremos cada una de estas características e las implementaremos en un Proyecto de Android Studio.

Estructura del Proyecto de Ejemplo de Android TextInputLayout

Esta es una aplicación de actividad única. Realizaremos todo dentro del diseño, la actividad y los archivos styles.xml y colors.xml. En primer lugar, agregue la dependencia para la biblioteca de soporte de diseño dentro del archivo build.gradle como se muestra a continuación.

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

Activar/Desactivar Sugerencias Flotantes

Las sugerencias flotantes están habilitadas de forma predeterminada en un TextInputLayout. Para desactivarlas, necesitamos agregar el siguiente atributo dentro de la etiqueta: app:hintEnabled="false". El código XML a continuación es del diseño activity_main.xml y tiene tres 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>

El tercer campo EditText tiene la pista flotante desactivada. Veamos la salida que nos da el código anterior:

Habilitar/Deshabilitar la animación de la pista flotante

Similar a la característica anterior, la animación de la pista flotante está habilitada por defecto. Para desactivarla, necesitamos agregar el siguiente atributo dentro de la etiqueta TextInputLayout. app:hintAnimationEnabled="false" El siguiente código XML es del diseño activity_main.xml y tiene campos EditText para cualquiera de los 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>

La salida del código anterior se muestra a continuación. Cabe mencionar que el segundo campo EditText no anima la pista flotante al enfocarse.

Estilizando la apariencia del texto de la pista

Para usar un textColor y textSize personalizados para las sugerencias, se utiliza el siguiente atributo: app:hintTextAppearance="@style/HintText" El estilo HintText se escribe dentro del archivo styles.xml como se muestra a continuación

<style name="HintText" parent="TextAppearance.Design.Hint">
        <item name="android:textSize">16sp</item>
        <item name="android:textColor">@color/colorPrimary</item>
    </style>

El siguiente código XML es del diseño activity_main.xml y tiene campos EditText para cualquiera de los casos (con/sin 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>

La salida del código anterior se muestra a continuación.

Contador de caracteres

El contador de caracteres es una característica utilizada por muchas aplicaciones (¿Recuerdas el límite de caracteres de Twitter?). Establece app:counterEnabled en true y app:counterMaxLength con el número máximo de caracteres que deseas en el TextInputLayout. Por defecto, el contador de caracteres se muestra debajo del EditText (en la esquina inferior derecha) y al escribir este tutorial, no hay forma de cambiar la posición todavía. Estilizar el contador es similar a estilizar el texto de sugerencia. app:counterTextAppearance es el atributo utilizado esta vez. Hemos agregado el siguiente estilo dentro del archivo styles.xml en nuestro proyecto.

<style name="CounterText" parent="TextAppearance.Design.Counter">
        <item name="android:textSize">16sp</item>
        <item name="android:textColor">@color/my_pink</item>
    </style>

El siguiente código XML es del diseño activity_main.xml y tiene campos EditText con un contador de caracteres predeterminado y uno 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>

El resultado del código anterior se muestra a continuación. Observemos detenidamente el resultado anterior.

  • El primer campo EditText cambia su color de texto textColor, el color de pista textColor y el color del indicador cuando se supera el límite de caracteres.
  • El segundo campo EditText hace lo mismo, pero también cambia el color de texto personalizado custom textColor y el tamaño de texto personalizado custom textSize cuando se excede el límite.

Para especificar el estilo que necesitamos cuando el contador de caracteres supera su límite, debemos usar el atributo counterFlow, que veremos a continuación.

Desbordamiento del Contador de Caracteres

Como vimos anteriormente, cuando el recuento de caracteres supera el límite definido, el texto del contador utiliza los atributos definidos en counterFlow. Si los atributos no estuvieran presentes, se adherirá a los predeterminados, como vimos en el resultado anterior. Necesitamos usar el siguiente parámetro app:counterOverflowTextAppearance. El estilo para CounterOverflow está presente dentro de 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>

Añade el siguiente fragmento de código al diseño 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 a ejecutar la aplicación nuevamente.

Etiqueta de Error

Configurar app:errorEnabled a true nos permite mostrar un texto de error en condiciones debajo de nuestro campo EditText. Para dar estilo al texto de error, usaríamos el atributo app:errorTextAppearance y agregar el siguiente código dentro de nuestro archivo styles.xml.

<style name="ErrorText" parent="TextAppearance.Design.Error">
        <item name="android:textSize">16sp</item>
        <item name="android:textColor">@color/my_black</item>
    </style>

El siguiente código XML es del diseño activity_main.xml y tiene campos EditText para una etiqueta de error predeterminada y una 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 mostrar el texto de error, tendremos que llamar al método setError(String) en una instancia de TextInputLayout en nuestra clase MainActivity.java, como se muestra a continuación.

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);

            }
        });


    }
}

En el código anterior, agregamos un TextChangedListener (que implementa TextWatcher) en cada instancia de TextInputEditText. Mostramos la etiqueta de error cuando el recuento de caracteres actual excede el límite máximo del contador. Para borrar la etiqueta de error, establecemos el valor dentro de setError() como null. La salida que nos da el código anterior es: Nota: El indicador del campo de texto utiliza el mismo color que la etiqueta de error. Anula el color establecido por counterOverflow, por lo que tiene la mayor prioridad.

Alternar visibilidad de contraseña

Al establecer app:passwordToggleEnabled en true, puedes mostrar/ocultar la contraseña. Para cambiar el color del ícono, utiliza app:passwordToggleTint. El siguiente código XML es del diseño activity_main.xml y tiene campos de EditText para alternar la visibilidad de la contraseña (con el ícono predeterminado y con un tinte).

<?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>

La salida mostrada por el código anterior es: Nota: Podemos usar nuestros propios iconos personalizados desde la alternancia de visibilidad de contraseña usando app:passwordToggleDrawable. Esto pone fin a este tutorial. Hemos cubierto todas las características principales presentes en TextInputLayout. Puedes descargar el Proyecto de Ejemplo de Android TextInputLayout desde el enlace a continuación. Incluye cada uno de los fragmentos de código mencionados anteriormente.

Descargar Proyecto de Android TextInputLayout

Referencia: Documentación Oficial de Android

Source:
https://www.digitalocean.com/community/tutorials/android-textinputlayout-example