[TUT] Validate EditText User Input with Shake Feedback

I was recently watching the Google App Clinic and noticed one of the apps Zoum Tasks had this really cool feature where when the user enters an email address into an EditText, if it was invalid then the EditText would shake! I thought this was really cool and wondered how it was implemented so I gave it a go myself and here it is!

So what are we going to do:

  • Create a layout where you can enter an email address and click done
  • Create a custom edittext that can validate input and give feedback
  • Create an animation to ‘shake’ our edittext
  • Create an email address validator to be our guardian at the gates!
It's got a much more natural shake implemented on the device, this is just an illustration.
It’s got a much more natural shake implemented on the device, this is just an illustration.

Let’s do it!

First let’s start with email validation. For this simple example user input is a valid email if it contains an @ symbol. (keeping it simple).

EmailAddressValidator.java

package com.blundell.tutorial.util;

import com.blundell.tutorial.ui.widget.ValidationEditText.Validator;

/**
 * This is an Email Address Validator, you can validate anything that goes into an EditText just implement Validator
 * 
 * @author Blundell
 * 
 */
public class EmailAddressValidator implements Validator {

	/**
	 * Simple validation for Tutorial. If it has an @ sign then it is a valid email address
	 */
	@Override
	public boolean validate(String input) {
		if (input.contains("@")) {
			return true;
		}
		return false;
	}

}

The EmailAddressValidator implements Validator, we will come to the code for this later. This is so you can use different validators with different EditTexts (say you had an email address and a phone number EditText on the same screen).

Next is the custom EditText, this is called ValidationEditText it has two methods. 1 for setting the validation to use (i.e. validate a phone number or validate an email address) and 2 to ask it to validate (i.e. when a done button is pressed).

ValidationEditText.java

package com.blundell.tutorial.ui.widget;

import android.content.Context;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.animation.*;
import android.view.inputmethod.EditorInfo;
import android.widget.EditText;
import android.widget.TextView;

/**
 * This EditText will check its input from the user against the Validator you use with setValidator()
 * 
 * If it is valid input the method will return true
 * 
 * If it is invalid input the method will return false and 'shake' the EditText
 * 
 * @author Blundell
 * 
 */
public class ValidationEditText extends EditText {

	private Validator validator;

	public interface Validator {
		boolean validate(String input);
	}

	public ValidationEditText(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		init();
	}

	public ValidationEditText(Context context, AttributeSet attrs) {
		super(context, attrs);
		init();
	}

	public ValidationEditText(Context context) {
		super(context);
		init();
	}

	public void setValidator(Validator validator) {
		this.validator = validator;
	}

	public boolean hasValidInput() {
		if (validator == null) {
			throw new InstantiationError("Please set a validator first, using setValidator()");
		}
		boolean valid = validator.validate(getText().toString());

		if (!valid) {
			notifyUser();
		}

		return valid;
	}

	private void notifyUser() {
		// From XML Animation (recommended)
//		Animation shake = AnimationUtils.loadAnimation(getContext(), R.anim.shake);
		// Programmatic Animation
		Animation shake = new TranslateAnimation(0, 5, 0, 0);
		shake.setInterpolator(new CycleInterpolator(5));
		shake.setDuration(300);

		startAnimation(shake);
	}

	/**
	 * Optional - but recommended
	 * 
	 * This will check the input when he user hits the 'done' button on the keyboard
	 */
	private void init() {
		setOnEditorActionListener(new OnEditorActionListener() {
			@Override
			public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
				if (EditorInfo.IME_ACTION_DONE == actionId) {
					hasValidInput();
				}
				return false;
			}
		});
	}

}

So that you can copy and paste code, the above uses a programmatic animation but in a real project, I would put the animation in the resources folder (like in the sample project at the bottom).
The ValidationEditText also holds the interface that any validation util has to implement. To use ValidationEditText call setValidator() when you first create the view, then after the user has finished typing call hasValidInput() which will tell you true or false if it is valid.

In the XML view I have declared the EditText to use the imeOption actionDone, meaning a ‘done’ button will appear in the corner. When this is clicked it will also validate the input and shake if it is incorrect.

Just the formallity of showing you the XML layout, slightly different to normal because you are using a custom view:

activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:tools="http://schemas.android.com/tools"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:orientation="vertical"
  android:padding="10dip" >

  <TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/hello_world" />

  <com.blundell.tutorial.ui.widget.ValidationEditText
    android:id="@+id/main_et_email_address"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:hint="@string/main_et_hint_email_address"
    android:imeOptions="actionDone"
    android:inputType="textEmailAddress"
    android:singleLine="true" />

  <Button
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:onClick="onDoneClicked"
    android:text="@string/main_btn_done" />

</LinearLayout>

And finally the MainActivity itself. Here you reference the ValidationEditText, set your validator, set the onClick listener for your Done button and then validate the user input when this is clicked.:

MainActivity.java

package com.blundell.tutorial.ui;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;

import com.blundell.tutorial.R;
import com.blundell.tutorial.ui.widget.ValidationEditText;
import com.blundell.tutorial.util.EmailAddressValidator;

public class MainActivity extends Activity {

	private ValidationEditText emailAddressInputEditText;

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

		emailAddressInputEditText = (ValidationEditText) findViewById(R.id.main_et_email_address);
		emailAddressInputEditText.setValidator(new EmailAddressValidator());
	}

	public void onDoneClicked(View btn) {
		if (emailAddressInputEditText.hasValidInput()) {
			Toast.makeText(this, "Success! Carry on with app...", Toast.LENGTH_LONG).show();
		}
	}

}

And that’s it, your view should shake if you don’t enter a valid email address.

Here is the Git Repo Source

Here is the Eclipse Project Source

Any questions just ask!

One thought on “[TUT] Validate EditText User Input with Shake Feedback

  1. Nice tutorial and code. I wanted to just that and you certainly saved me a lot of time. Thanks a lot! Instead of creating a CustomView Class, I just startAnimation whenever some data doesn’t pass validation, but that’s just me. Cheers!

Leave a Reply

Your email address will not be published. Required fields are marked *