EditText Floating Labels – Android Material Design

FLoating label first introduced in HTML5/jquery animation but now it can be implemented in android also.
Firstly the label is seen as placeholder within the text box and as soon as user start inputting the text , the placeholder start animates towards the label position.

Below, in this article, we demonstrate the action of floating labels for EditText in android:

TextInputLayout

TextInputLayout, a new element design support library of android, was introduced to implement the floating label on EditText.
TextInputLayout works by taking the value of android:hint and then assigned that android:hint value to EditText and which then is displayed as floating label.
To implement the floating label just wrap the EditText by TextInputLayout and an error message is set to the EditText by using setErrorEnabled() and setError() methods.

 <android.support.design.widget.TextInputLayout android:id="@+id/input_layout_name" android:layout_width="match_parent" android:layout_height="wrap_content">

            <EditText android:id="@+id/input_name" android:layout_width="match_parent" android:layout_height="wrap_content" android:singleLine="true" android:hint="@string/hint_name" />
        </android.support.design.widget.TextInputLayout>

Simple Form Validation Example

We will show floating labels in action by creating a simple android application form to understand the real use of the TextInputLayout. This simple form will have floating labels, input validations and error messages enabled in the application.

1. Open Android Studio and create new project by going to File ⇒ New Project.

2. Then edit build.gradle and add design support library dependency.

com.android.support:design:23.0.1

dependencies {
    compile fileTree(include: ['*.jar'], dir: 'libs')
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:24.2.0'
    compile 'com.android.support:design:24.2.0'
}

3. Follow our tutorial here to implement the material design theme in your android app, however, this is an optional step and you can skip it also.

4. Edit strings.xml file and insert the following string values located under res ⇒ values.

<resources>
    <string name="app_name">Floating Label EditText</string>

    <string name="action_settings">Settings</string>
    <string name="hint_name">Full Name</string>
    <string name="hint_email">Email</string>
    <string name="hint_password">Password</string>
    <string name="btn_sign_up">Sign Up</string>
    <string name="err_msg_name">Enter your full name</string>
    <string name="err_msg_email">Enter valid email address</string>
    <string name="err_msg_password">Enter the password</string>
</resources>

5. Edit the layout file that is activity_main.xml of your main activity and copy paste the below layout. The main purpose of the code is to make a simple form having 3 input fields. In the below code you can see the EditText is wrapped by TextInputLayout.

<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent">

    <android.support.design.widget.AppBarLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

        <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="?attr/colorPrimary" app:layout_scrollFlags="scroll|enterAlways" app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />
    </android.support.design.widget.AppBarLayout>

    <LinearLayout android:layout_width="fill_parent" android:layout_height="match_parent" android:layout_marginTop="?attr/actionBarSize" android:orientation="vertical" android:paddingLeft="20dp" android:paddingRight="20dp" android:paddingTop="60dp">

        <android.support.design.widget.TextInputLayout android:id="@+id/input_layout_name" android:layout_width="match_parent" android:layout_height="wrap_content">

            <EditText android:id="@+id/input_name" android:layout_width="match_parent" android:layout_height="wrap_content" android:singleLine="true" android:hint="@string/hint_name" />
        </android.support.design.widget.TextInputLayout>

        <android.support.design.widget.TextInputLayout android:id="@+id/input_layout_email" android:layout_width="match_parent" android:layout_height="wrap_content">

            <EditText android:id="@+id/input_email" android:layout_width="match_parent" android:layout_height="wrap_content" android:inputType="textEmailAddress" android:hint="@string/hint_email" />
        </android.support.design.widget.TextInputLayout>

        <android.support.design.widget.TextInputLayout android:id="@+id/input_layout_password" android:layout_width="match_parent" android:layout_height="wrap_content">

            <EditText android:id="@+id/input_password" android:layout_width="match_parent" android:layout_height="wrap_content" android:inputType="textPassword" android:hint="@string/hint_password" />
        </android.support.design.widget.TextInputLayout>

        <Button android:id="@+id/btn_signup" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/btn_sign_up" android:background="@color/colorPrimary" android:layout_marginTop="40dp" android:textColor="@android:color/white"/>

    </LinearLayout>

</android.support.design.widget.CoordinatorLayout>

6. Edit the MainActivity.java file and implement the following changes. The changes include, adding few methods for validating the user entered data like name, email and password. Assign a TextWatcher to all the edit texts for validating the inputs while user is still typing in the textbox. To display the error message instantly when the input is invalid or empty, setError() methods is called on to edit text.

package com.devappandroid.floatingedit;

import android.os.Bundle;
import android.support.design.widget.TextInputLayout;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

    private Toolbar toolbar;
    private EditText inputName, inputEmail, inputPassword;
    private TextInputLayout inputLayoutName, inputLayoutEmail, inputLayoutPassword;
    private Button btnSignUp;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        inputLayoutName = (TextInputLayout) findViewById(R.id.input_layout_name);
        inputLayoutEmail = (TextInputLayout) findViewById(R.id.input_layout_email);
        inputLayoutPassword = (TextInputLayout) findViewById(R.id.input_layout_password);
        inputName = (EditText) findViewById(R.id.input_name);
        inputEmail = (EditText) findViewById(R.id.input_email);
        inputPassword = (EditText) findViewById(R.id.input_password);
        btnSignUp = (Button) findViewById(R.id.btn_signup);

        inputName.addTextChangedListener(new MyTextWatcher(inputName));
        inputEmail.addTextChangedListener(new MyTextWatcher(inputEmail));
        inputPassword.addTextChangedListener(new MyTextWatcher(inputPassword));

        btnSignUp.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                submitForm();
            }
        });
    }

    /**
     * Validating form
     */
    private void submitForm() {
        if (!validateName()) {
            return;
        }

        if (!validateEmail()) {
            return;
        }

        if (!validatePassword()) {
            return;
        }

        Toast.makeText(getApplicationContext(), "Thank You!", Toast.LENGTH_SHORT).show();
    }

    private boolean validateName() {
        if (inputName.getText().toString().trim().isEmpty()) {
            inputLayoutName.setError(getString(R.string.err_msg_name));
            requestFocus(inputName);
            return false;
        } else {
            inputLayoutName.setErrorEnabled(false);
        }

        return true;
    }

    private boolean validateEmail() {
        String email = inputEmail.getText().toString().trim();

        if (email.isEmpty() || !isValidEmail(email)) {
            inputLayoutEmail.setError(getString(R.string.err_msg_email));
            requestFocus(inputEmail);
            return false;
        } else {
            inputLayoutEmail.setErrorEnabled(false);
        }

        return true;
    }

    private boolean validatePassword() {
        if (inputPassword.getText().toString().trim().isEmpty()) {
            inputLayoutPassword.setError(getString(R.string.err_msg_password));
            requestFocus(inputPassword);
            return false;
        } else {
            inputLayoutPassword.setErrorEnabled(false);
        }

        return true;
    }

    private static boolean isValidEmail(String email) {
        return !TextUtils.isEmpty(email) && android.util.Patterns.EMAIL_ADDRESS.matcher(email).matches();
    }

    private void requestFocus(View view) {
        if (view.requestFocus()) {
            getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
        }
    }

    private class MyTextWatcher implements TextWatcher {

        private View view;

        private MyTextWatcher(View view) {
            this.view = view;
        }

        public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
        }

        public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
        }

        public void afterTextChanged(Editable editable) {
            switch (view.getId()) {
                case R.id.input_name:
                    validateName();
                    break;
                case R.id.input_email:
                    validateEmail();
                    break;
                case R.id.input_password:
                    validatePassword();
                    break;
            }
        }
    }
}