We all use EditText
when we want user input. We can provide a hint to the user as to what to enter in a particular EditText
. However, once the user starts typing, the hint is gone. Sometimes, this causes confusion to the app user when he forgets which field he was interacting with. However, to the rescue of the Android developers, Floating Label EditText was introduced with the material design library. It initially shows the label as a hint, but when user starts entering a value in the EditText
, that hint turns into a floating label as the name suggests.
In this tutorial, we will discuss how to implement Android Floating Label EditText using the material design library.
The Floating Label EditText is implemented by wrapping an android.support.design.widget.TextInputLayout
around the EditText
. TextInputLayout
is a widget which is used specifically to wrap an EditText
and render floating labels. We also use its functions to show errors for the particular EditText
it surrounds.
Pre-requisites
- Android Studio installed on your PC (Unix or Windows).
- A real time Android device (Smartphone or Tablet) configured with Android Studio.
Creating a New Project and Adding Material Design Library
compile 'com.android.support:design:23.0.0'
- Go to File → New → New Project and enter your Application Name.
- Enter Company Domain, this is used to uniquely identify your App’s package worldwide.
- Choose project location and minimum SDK and on the next screen choose Empty Activity, since we would be adding most of the code Ourselves. Then, Click on Next.
- Choose an Activity Name. Make sure Generate Layout File check box is selected, otherwise we have to generate it ourselves. Then, click on Finish. We have chosen the Activity Name as
SignUpActivity
, since we are mimicking the signup page in used in almost all the apps. This is the best use case for the Floating Label EditText. - To add support for
TextInputLayout
to your project, add the following dependency in your App’s build.gradle
file. - Gradle will configure your project and resolve the dependencies. Once it is complete, proceed to the next steps.
We are creating a dummy signup page for this Android Floating Label EditText example. We will make use of EditTexts, each of which will be wrapped in a TextInputLayout
. After completion, the layout will look as in the below figure.
Adding the Layout
Open activity_sign_up.xml and add the following code.
activity_sign_up.xml
="1.0"="utf-8"
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center"
android:orientation="vertical"
android:padding="10dp" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:orientation="vertical"
android:paddingLeft="20dp"
android:paddingRight="20dp" >
<android.support.design.widget.TextInputLayout
android:id="@+id/signup_input_layout_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginTop="10dp">
<EditText
android:id="@+id/signup_input_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:hint="Name"/>
</android.support.design.widget.TextInputLayout>
<android.support.design.widget.TextInputLayout
android:id="@+id/signup_input_layout_email"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginTop="10dp">
<EditText
android:id="@+id/signup_input_email"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:inputType="textEmailAddress"
android:hint="Email" />
</android.support.design.widget.TextInputLayout>
<android.support.design.widget.TextInputLayout
android:id="@+id/signup_input_layout_password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginTop="10dp">
<EditText
android:id="@+id/signup_input_password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:inputType="textPassword"
android:hint="@string/hint_password" />
</android.support.design.widget.TextInputLayout>
<android.support.design.widget.TextInputLayout
android:id="@+id/signup_input_layout_dob"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginTop="10dp">
<EditText
android:id="@+id/signup_input_dob"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:singleLine="true"
android:hint="@string/hint_dob"/>
</android.support.design.widget.TextInputLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="20dp">
<TextView
android:id="@+id/gender_textview"
android:paddingRight="15dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hint_gender"
android:fontFeatureSettings="@string/hint_password"
android:textSize="20dp"
android:fontFamily="@string/hint_password"/>
<RadioGroup
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@+id/gender_textview"
android:orientation="horizontal"
>
<RadioButton
android:id="@+id/male_radio_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/male"
android:checked="true"
/>
<RadioButton
android:id="@+id/female_radio_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text = "@string/female"
/>
</RadioGroup>
</RelativeLayout>
<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/colorPrimaryDark"
android:layout_marginTop="40dp"
android:textColor="@android:color/white"/>
</LinearLayout>
</LinearLayout>
The above layout is pretty self explanatory, we have EditText
for Name, Email, Password and Date of Birth and then we have a RadioGroup
for getting the input for gender. These are the typical inputs you will get from the user to register her on your app or website. At last, we have a Sign Up!! button that will be used to submit the button.
Adding the Functionality
In the SignUpActivity.java, we first declare variables for the EditText
and TextInputLayout
.
Open SignUpActivity.java and add the following code.
package com.androidtutorialpoint.floatinglabeledittext;
import android.content.Context;
import android.os.Bundle;
import android.os.Vibrator;
import android.support.design.widget.TextInputLayout;
import android.support.v7.app.AppCompatActivity;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.view.View;
import android.view.WindowManager;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
public class SignUpActivity extends AppCompatActivity {
private static final String TAG = "RegisterActivity";
private Vibrator vib;
Animation animShake;
private EditText signupInputName, signupInputEmail, signupInputPassword, signupInputDOB;
private TextInputLayout signupInputLayoutName, signupInputLayoutEmail,
signupInputLayoutPassword,signupInputLayoutDOB;
private Button btnSignUp;
Now we reference these Widgets in the OnCreate()
method of the SignUpActvity.java.
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sign_up);
signupInputLayoutName = (TextInputLayout) findViewById(R.id.signup_input_layout_name);
signupInputLayoutEmail = (TextInputLayout) findViewById(R.id.signup_input_layout_email);
signupInputLayoutPassword = (TextInputLayout) findViewById(R.id.signup_input_layout_password);
signupInputLayoutDOB = (TextInputLayout) findViewById(R.id.signup_input_layout_dob);
signupInputName = (EditText) findViewById(R.id.signup_input_name);
signupInputEmail = (EditText) findViewById(R.id.signup_input_email);
signupInputPassword = (EditText) findViewById(R.id.signup_input_password);
signupInputDOB = (EditText) findViewById(R.id.signup_input_dob);
btnSignUp = (Button) findViewById(R.id.btn_signup);
animShake = AnimationUtils.loadAnimation(getApplicationContext(),R.anim.shake);
vib = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
btnSignUp.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
submitForm();
}
});
}
Note that we have used the animation to shake the EditText
in the case of any invalid input. To add animation, create an animation resource file in the values folder and add the following file:
shake.xml
="1.0"="utf-8"
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/overshoot_interpolator"
android:fillAfter="true">
<translate
android:startOffset="100"
android:fromXDelta="0%p"
android:toXDelta="5%p"
android:duration="100" />
<translate
android:startOffset="150"
android:fromXDelta="0%p"
android:toXDelta="-10%p"
android:duration="160" />
<translate
android:startOffset="260"
android:fromXDelta="0%p"
android:toXDelta="10%p"
android:duration="170" />
<translate
android:startOffset="380"
android:fromXDelta="0%p"
android:toXDelta="-10%p"
android:duration="180" />
<translate
android:startOffset="510"
android:fromXDelta="0%p"
android:toXDelta="5%p"
android:duration="140" />
</set>
When there is an Invalid input, the EditText
will shake and phone will vibrate to alert the user about the error. For adding the Vibrate
functionality, add the following permission in AndroidManifest.xml.
AndroidManifest.xml
<uses-permission android:name="android.permission.VIBRATE"></uses-permission>
In the OnClickListener
, we are calling the function submitForm()
, which will validate the user input and throw an error in if it finds invalid data.
Add the following code in the SignUpActvity.java after the onCreate()
method.
SignUpActivity.java
private void submitForm() {
if (!checkName()) {
signupInputName.setAnimation(animShake);
signupInputName.startAnimation(animShake);
vib.vibrate(120);
return;
}
if (!checkEmail()) {
signupInputEmail.setAnimation(animShake);
signupInputEmail.startAnimation(animShake);
vib.vibrate(120);
return;
}
if (!checkPassword()) {
signupInputPassword.setAnimation(animShake);
signupInputPassword.startAnimation(animShake);
vib.vibrate(120);
return;
}
if (!checkDOB()) {
signupInputDOB.setAnimation(animShake);
signupInputDOB.startAnimation(animShake);
vib.vibrate(120);
return;
}
signupInputLayoutName.setErrorEnabled(false);
signupInputLayoutEmail.setErrorEnabled(false);
signupInputLayoutPassword.setErrorEnabled(false);
signupInputLayoutDOB.setErrorEnabled(false);
Toast.makeText(getApplicationContext(),
"You are successfully Registered !!", Toast.LENGTH_SHORT).show();
}
private boolean checkName() {
if (signupInputName.getText().toString().trim().isEmpty()) {
signupInputLayoutName.setErrorEnabled(true);
signupInputLayoutName.setError(getString(R.string.err_msg_name));
signupInputName.setError(getString(R.string.err_msg_required));
return false;
}
signupInputLayoutName.setErrorEnabled(false);
return true;
}
private boolean checkEmail() {
String email = signupInputEmail.getText().toString().trim();
if (email.isEmpty() || !isValidEmail(email)) {
signupInputLayoutEmail.setErrorEnabled(true);
signupInputLayoutEmail.setError(getString(R.string.err_msg_email));
signupInputEmail.setError(getString(R.string.err_msg_required));
requestFocus(signupInputEmail);
return false;
}
signupInputLayoutEmail.setErrorEnabled(false);
return true;
}
private boolean checkPassword() {
if (signupInputPassword.getText().toString().trim().isEmpty()) {
signupInputLayoutPassword.setError(getString(R.string.err_msg_password));
requestFocus(signupInputPassword);
return false;
}
signupInputLayoutPassword.setErrorEnabled(false);
return true;
}
private boolean checkDOB() {
try {
boolean isDateValid = false;
String[] s = signupInputDOB.getText().toString().split("/");
int date = Integer.parseInt(s[0]);
int month = Integer.parseInt(s[1]);
if (date < 32 && month < 13)
isDateValid = true;
if (signupInputDOB.getText().toString().trim().isEmpty() && isDateValid) {
signupInputLayoutDOB.setError(getString(R.string.err_msg_dob));
requestFocus(signupInputDOB);
signupInputDOB.setError(getString(R.string.err_msg_required));
return false;
}
}catch(Exception ex){
signupInputLayoutDOB.setError(getString(R.string.err_msg_dob));
requestFocus(signupInputDOB);
return false;
}
signupInputDOB.setError(null);
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);
}
}
The submitForm()
method uses helper methods checkName()
, checkEmail()
, checkPassword()
and checkDOB()
and checks for presence of name, email, password and D.O.B, It also checks whether the email and D.O.B entered are valid.
Let’s briefly discuss about these methods.
checkName()
– Checks whether the mandatory field name is present or not. Otherwise, it calls setErrorEnabled(true)
on the signupInputLayoutName
to notify there is an error and setError(getString(R.string.err_msg_name))
to set the error message for the signupInputLayoutName
. Additionally, we are also setting the error for the EditText
using setError(getString(R.string.err_msg_required))
method. Then, we are returning false
to the submitForm()
so that it invokes the shake animation. checkEmail()
– This method is similar to checkName()
method, it additionally calls the isValidEmail()
to check whether the entered email is valid or not. checkPassword()
– This method is also similar to checkName()
method. It checks whether the Password
field is left blank or not. In case it is blank, it will raise an error and return false
. checkDOB()
– This method checks whether the Date of Birth entered by the user is valid or not.
We have used the following string
resources.
strings.xml
<resources>
<string name="app_name">FloatingLabelEditText</string>
<string name="hint_dob">Enter D.O.B (DD/MM/YYYY)</string>
<string name="hint_password">Password</string>
<string name="hint_gender">I am</string>
<string name="male">Male</string>
<string name="female">Female</string>
<string name="btn_sign_up">Sign Up !!</string>
<string name="err_msg_name">Please enter a Name</string>
<string name="err_msg_required">Valid Input Required</string>
<string name="err_msg_email">Please enter a Valid Email</string>
<string name="err_msg_password">Enter a Password</string>
<string name="err_msg_dob">Enter a valid D.O.B</string>
</resources>
Now run the app and test whether all the validations are fired or not. You have to test different test cases for testing whether the email and D.O.B validations are proper or not. Hope you liked this material design floating label edit text example tutorial.