time

Working with the EditText

Introduction

The EditText is the standard text entry widget in Android apps. If the user needs to enter text into an app, this is the primary way for them to do that.

An EditText is added to a layout with all default behaviors with the following XML:

<EditText
    android:id="@+id/etTitle"
    android:layout_height="wrap_content"
    android:layout_width="match_parent"/>

Note that an EditText is simply a thin extension of the TextView and inherits all of the same properties.

To retrieve the value of an EditText control from within your Activity, you can use the getText() method of the EditText class. For example, the following code retrieves a handle to the EditText control defined as etTitle:

EditText etTitle = (EditText) findViewById(R.id.etTitle);
String title = etTitle.getText().toString();

By default, any text contents within an EditText control is displayed as plain text. By setting inputType, we can facilitate input of different types of information, like phone numbers and passwords:

<EditText
    ...
    android:inputType="phone">
<EditText>

Most common input types include:

Type Description
textUri Text that will be used as a URI
textEmailAddress Text that will be used as an e-mail address
textPersonName Text that is the name of a person
textPassword Text that is a password that should be obscured
textVisiblePassword Text, next button, and no microphone input
number A numeric only field
phone For entering a phone number
date For entering a date
time For entering a time
textMultiLine Allow multiple lines of text in the field

You can set multiple inputType attributes if needed (separated by '|')

<EditText
    android:inputType="textCapSentences|textMultiline"/>

You can see a list of all available input types here.

Customization

We might want to limit the entry to a single-line of text (avoid newlines):

<EditText
    android:maxLines="1"
    android:lines="1"/>

You can limit the characters that can be entered into a field using the digits attribute:

<EditText
    android:inputType="number"
    android:digits="01"/>

This would restrict the digits entered to just "0" and "1".

We might want to limit the total number of characters with:

<EditText
    android:maxLength="5"/>

Using these properties we can define the expected input behavior for text fields.

Displaying floating label

Traditionally, the EditText hides the hint message after the user starts typing. In addition, any validation error messages had to be managed manually by the developer.

Starting with Android M and the design support library, the TextInputLayout can be used to setup a floating label to display hints and error messages. First, wrap the EditText in a TextInputLayout:

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

    <EditText
        android:id="@+id/etTitle"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:ems="10"
        android:hint="Title" />
</android.support.design.widget.TextInputLayout>

We can also use the TextInputLayout to display error messages using the setError and setErrorEnabled properties in the activity at runtime:

final TextInputLayout tilTitle = (TextInputLayout) findViewById(R.id.tilTitle);

tilTitle.getEditText().addTextChangedListener(new TextWatcher() {
    // ...
    @Override
    public void onTextChanged(CharSequence text, int start, int count, int after) {
        if (text.length() > 0 && text.length() <= 4) {
            tilTitle.setError(getString(R.string.title_required));
            tilTitle.setErrorEnabled(true);
        } else {
            tilTitle.setErrorEnabled(false);
        }
    }

    @Override
    public void beforeTextChanged(CharSequence s, int start, int count, int after) {}

    @Override
    public void afterTextChanged(Editable s) {}
});

Here we use the addTextChangedListener to watch as the value changes to determine when to display the error message or revert to the hint.

Listening for EditText input

There are a few common listeners for input fields:

  • addTextChangedListener - fires each time the text in the field is being changed.
  • setOnEditorActionListener - fires when an "action" button on the soft keyboard is pressed.

TextChangedListener

If you want to handle an event as the text in the view is being changed, you only need to look as far as the addTextChangedListener method on an EditText:

EditText etTitle = (EditText) findViewById(R.id.etTitle);

etTitle.addTextChangedListener(new TextWatcher() {
    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) {
        // Fires right as the text is being changed (even supplies the range of text)
    }

    @Override
    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
        // Fires right before text is changing
    }

    @Override
    public void afterTextChanged(Editable s) {
        // Fires right after the text has changed
        tvTitle.setText(s.toString());
    }
});

This is great for any time you want to have the UI update as the user enters text.

OnEditorActionListener

Another case is when you want an action to occur once the user has finished typing text with the Soft Keyboard. Keep in mind that this is especially useful when you can see the virtual keyboard which is disabled by default in the emulator but can be enabled as explained in this graphic.

First, we need to setup an "action" button for our text field. To setup an "action button" such as a Done button on the Soft Keyboard, simply configure your EditText with the following properties:

<EditText
    android:id="@+id/etTitle"
    android:inputType="text"
    android:singleLine="true"
    android:imeOptions="actionDone"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
    <requestFocus />
</EditText>

In particular, singleLine and imeOptions are required for the Done button to display. Now, we can hook into a editor listener for when the done button is pressed with:

etTitle.setOnEditorActionListener(new OnEditorActionListener() {
    @Override
    public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
        if (actionId == EditorInfo.IME_ACTION_DONE) {
            String text = v.getText().toString();
            Toast.makeText(activity, text, Toast.LENGTH_SHORT).show();

            // hide keyboard
            //InputMethodManager inputManager = (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE);
            //inputManager.hideSoftInputFromWindow(activity.getCurrentFocus().getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);

            return true;
        }
        return false;
    }
});

This is often great whenever a user needs to type text and then explicitly have an action performed when they are finished. There are many imeOptions for different situations.

Adding character counting

TextInputLayout since the announcement of support design library v23.1 also can expose a character counter for an EditText defined within it. The counter will be rendered below the EditText and can change colors of both the line and character counter if the maximum number of characters has been exceeded:

The TextInputLayout simply needs to define app:counterEnabled and app:CounterMaxLength in the XML attributes. These settings can also be defined dynamically through setCounterEnabled() and setCounterMaxLength():

<android.support.design.widget.TextInputLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:counterEnabled="true"
    app:counterMaxLength="10"
    app:counterTextAppearance="@style/counterText"
    app:counterOverflowTextAppearance="@style/counterOverride">
    <EditText
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:ems="10"
       android:hint="Title" />
</android.support.design.widget.TextInputLayout>

The counter text and overflow text can also have their own text styles by defining app:counterTextAppearance and app:counterOverflowTextAppearance. We can use textColor, textSize, and fontFamily to help change the color, size, or font. Add following snippets to res/values/styles.xml.

<style name="counterText">
    <item name="android:textColor">#aa5353cc</item>
</style>

<style name="counterOverride">
    <item name="android:textColor">#ff0000</item>
</style>

Shake EditText on error

The animation specification is created in XML files in the anim directory. In this example, we want the text entry field to be able to shake either left to right. So, we create an animation, res/anim/shake.xml:

<?xml version="1.0" encoding="utf-8"?>
<translate
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:fromXDelta="0"
    android:toXDelta="10"
    android:duration="1000"
    android:interpolator="@anim/cycler"/>

The interpolator - the function that drives the animation. It's contained in another file, res/anim/cycler.xml, shown here:

<?xml version="1.0"?>
<cycleInterpolator
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:cycles="2"/>

To apply the animations to EditText component, you need a reference to it. You can, of course, use the common findViewById(R.id.*). You can also use the Activity method getCurrentFocus() if you are dealing with the current input (focused) View component; this avoids coupling to the name of a particular component, if you know that your animation will always apply to the current input object.

etTitle.startAnimation(AnimationUtils.loadAnimation(getApplicationContext(), R.anim.shake));

The shaking effect is convenient for drawing the user’s attention to an input that is incorrect

Stylization

EditText control can be styled using styles.xml file to make it more attractive and stylish.

Add a style element as below in your res>values>styles.xml :

<style name="MyEditTextStyle" parent="android:Widget.EditText">
    <item name="android:textColor">#400000</item>
    <item name="android:textStyle">bold</item>
    <item name="android:padding">10dp</item>
    <item name="android:typeface">monospace</item>
    <item name="android:background">@android:drawable/editbox_background_normal</item>
    <item name="android:textSize">20sp</item>
</style>

And supply this style name to your EditText control in design file:

<EditText
    android:id="@+id/etTitle"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="5dp"
    android:hint="Enter your title"
    android:inputType="text"
    android:textColor="#000" 
    style="@style/MyEditTextStyle"/>

How to disable drag event on EditText

editText.setOnDragListener(new OnDragListener() {
    @Override
    public boolean onDrag(View v, DragEvent event) {
        return true;
    }
});

Returns true if the drag event was handled successfully, or false if the drag event was not handled. Note that false will trigger the View to call its onDragEvent() handler.

comments powered by Disqus