[android] How to create EditText with cross(x) button at end of it?

Is there any widget like EditText which contains a cross button, or is there any property for EditText by which it is created automatically? I want the cross button to delete whatever text written in EditText.

This question is related to android android-edittext

The answer is


Here is the simple complete solution in kotlin.

This whole layout will be your search bar

<RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="35dp"
        android:layout_margin="10dp"
        android:background="@drawable/your_desired_drawable">

        <EditText
            android:id="@+id/search_et"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_alignParentStart="true"
            android:layout_toStartOf="@id/clear_btn"
            android:background="@null"
            android:hint="search..."
            android:imeOptions="actionSearch"
            android:inputType="text"
            android:maxLines="1"
            android:paddingStart="15dp"
            android:paddingEnd="10dp" />

        <ImageView
            android:id="@+id/clear_btn"
            android:layout_width="20dp"
            android:layout_height="match_parent"
            android:layout_alignParentEnd="true"
            android:layout_centerInParent="true"
            android:layout_marginEnd="15dp"
            android:visibility="gone"
            android:src="@drawable/ic_baseline_clear_24"/>

    </RelativeLayout>

Now this is the functionality of clear button, paste this code in onCreate method.

search_et.addTextChangedListener(object: TextWatcher {
            override fun beforeTextChanged(s:CharSequence, start:Int, count:Int, after:Int) {
            }
            override fun onTextChanged(s:CharSequence, start:Int, before:Int, count:Int) {
            }
            override fun afterTextChanged(s: Editable) {
                if (s.isNotEmpty()){
                    clear_btn.visibility = VISIBLE
                    clear_btn.setOnClickListener {
                        search_et.text.clear()
                    }
                }else{
                    clear_btn.visibility = GONE
                }
            }
        })

Here is complete library with the widget: https://github.com/opprime/EditTextField

To use it you should add the dependency:

compile 'com.optimus:editTextField:0.2.0'

In the layout.xml file you can play with the widget settings:

xmlns:app="http://schemas.android.com/apk/res-auto"
  • app:clearButtonMode,can has such values: never always whileEditing unlessEditing

  • app:clearButtonDrawable

Sample in action:

enter image description here


I did the UI part like below:

<RelativeLayout
    android:layout_width="fill_parent"
    android:layout_height="50dp"
    android:layout_marginTop="9dp"
    android:padding="5dp">

    <EditText
        android:id="@+id/etSearchToolbar"
        android:layout_width="fill_parent"
        android:layout_height="match_parent"
        android:textSize="13dp"
        android:padding="10dp"
        android:textColor="@android:color/darker_gray"
        android:textStyle="normal"
        android:hint="Search"
        android:imeOptions="actionSearch"
        android:inputType="text"
        android:background="@drawable/edittext_bg"
        android:maxLines="1" />

    <ImageView
        android:id="@+id/ivClearSearchText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:layout_marginRight="6dp"
        android:src="@drawable/balloon_overlay_close"
        android:layout_alignParentRight="true"
        android:layout_alignParentEnd="true" />
</RelativeLayout>

edittext_bg.xml

<?xml version="1.0" encoding="utf-8"?>
<!-- res/drawable/rounded_edittext_focused.xml -->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:padding="10dp"
    android:shape="rectangle" >

    <solid android:color="#FFFFFF" />

    <stroke
        android:width="1dp"
        android:color="#C9C9CE" />

    <corners
        android:bottomLeftRadius="15dp"
        android:bottomRightRadius="15dp"
        android:topLeftRadius="15dp"
        android:topRightRadius="15dp" />

</shape>

balloon_overlay_close.pngenter image description here

Cross/Clear button hide/show:

searchBox.addTextChangedListener(new TextWatcher() {
    @Override
    public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {}

    @Override
    public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
        if(charSequence.length() > 0){
            clearSearch.setVisibility(View.VISIBLE);
        }else{
            clearSearch.setVisibility(View.GONE);
        }
    }

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

Handle search stuffs (i.e when user clicks search from soft key board)

searchBox.setOnEditorActionListener(new TextView.OnEditorActionListener() {
    @Override
    public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
        if (actionId == EditorInfo.IME_ACTION_SEARCH) {
            String contents = searchBox.getText().toString().trim();
            if(contents.length() > 0){
                //do search

            }else{
                //if something to do for empty edittext
            }

            return true;
        }
        return false;
    }
});

Clear/Cross button

clearSearch.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        searchBox.setText("");
    }
});

This is a kotlin solution. Put this helper method in some kotlin file-

fun EditText.setupClearButtonWithAction() {

    addTextChangedListener(object : TextWatcher {
        override fun afterTextChanged(editable: Editable?) {
            val clearIcon = if (editable?.isNotEmpty() == true) R.drawable.ic_clear else 0
            setCompoundDrawablesWithIntrinsicBounds(0, 0, clearIcon, 0)
        }

        override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) = Unit
        override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) = Unit
    })

    setOnTouchListener(View.OnTouchListener { _, event ->
        if (event.action == MotionEvent.ACTION_UP) {
            if (event.rawX >= (this.right - this.compoundPaddingRight)) {
                this.setText("")
                return@OnTouchListener true
            }
        }
        return@OnTouchListener false
    })
}

And then use it as following in the onCreate method and you should be good to go-

yourEditText.setupClearButtonWithAction()

BTW, you have to add R.drawable.ic_clear or the clear icon at first. This one is from google- https://material.io/tools/icons/?icon=clear&style=baseline


You can use this snippet with Jaydip answer for more than one button. just call it after getting a reference to the ET and Button Elements. I used vecotr button so you have to change the Button element to ImageButton:

private void setRemovableET(final EditText et, final ImageButton resetIB) {

        et.setOnFocusChangeListener(new View.OnFocusChangeListener() {
            @Override
            public void onFocusChange(View v, boolean hasFocus) {
                if (hasFocus && et.getText().toString().length() > 0)
                    resetIB.setVisibility(View.VISIBLE);
                else
                    resetIB.setVisibility(View.INVISIBLE);
            }
        });

        resetIB.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                et.setText("");
                resetIB.setVisibility(View.INVISIBLE);
            }
        });

        et.addTextChangedListener(new TextWatcher() {
            @Override
            public void afterTextChanged(Editable s) {}
            @Override
            public void beforeTextChanged(CharSequence s, int start,
                                          int count, int after) {
            }
            @Override
            public void onTextChanged(CharSequence s, int start,
                                      int before, int count) {
                if(s.length() != 0){
                    resetIB.setVisibility(View.VISIBLE);
                }else{
                    resetIB.setVisibility(View.INVISIBLE);
                }
            }
        });
    }

If you are in frame layout or you can create a frame layout I tried another approach....

<TextView
    android:id="@+id/inputSearch"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:drawableRight="@drawable/ic_actionbar"
    android:layout_alignParentBottom="true"
    android:layout_toRightOf="@+id/back_button"/>

<Button
    android:id="@+id/clear_text_invisible_button"
    android:layout_width="30dp"
    android:layout_height="30dp"
    android:layout_gravity="right|center_vertical"
    android:background="@color/transparent"
    android:layout_alignBaseline="@+id/inputSearch"
    android:layout_alignBottom="@+id/inputSearch"
    android:layout_alignRight="@+id/inputSearch"
    android:layout_alignEnd="@+id/inputSearch"
    android:layout_marginRight="13dp"
    />

This is an edit text where I put a cross icon as a right drawable and than UPON it I put a transparent button which clears text.


For drawable resource you can use standard android images :

http://androiddrawables.com/Menu.html

For example :

android:background="@android:drawable/ic_menu_close_clear_cancel"

2020 solution via Material Design Components for Android:

Add Material Components to your gradle setup:

Look for latest version from here: https://maven.google.com/

implementation 'com.google.android.material:material:1.1.0'

or if you havent updated to using AndroidX libs, you can add it this way:

implementation 'com.android.support:design:28.0.0'

Then

<com.google.android.material.textfield.TextInputLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:hint="@string/hint_text"
    app:endIconMode="clear_text">

  <com.google.android.material.textfield.TextInputEditText
      android:layout_width="match_parent"
      android:layout_height="wrap_content"/>

</com.google.android.material.textfield.TextInputLayout>

Pay attention to: app:endIconMode="clear_text"

As discussed here Material design docs


Use

android:drawableRight="@android:drawable/ic_input_delete"

If you happen to use DroidParts, I've just added ClearableEditText.

Here's what it looks like with a custom background & clear icon set to abs__ic_clear_holo_light from ActionBarSherlock:

enter image description here


Drawable x = getResources().getDrawable(R.drawable.x);
x.setBounds(0, 0, x.getIntrinsicWidth(), x.getIntrinsicHeight());
mEditText.setCompoundDrawables(null, null, x, null);

where, x is:

enter image description here


Just put close cross like drawableEnd in your EditText:

<EditText
     ...
    android:drawableEnd="@drawable/ic_close"
    android:drawablePadding="8dp"
     ... />

and use extension to handle click (or use OnTouchListener directly on your EditText):

fun EditText.onDrawableEndClick(action: () -> Unit) {
    setOnTouchListener { v, event ->
        if (event.action == MotionEvent.ACTION_UP) {
            v as EditText
            val end = if (v.resources.configuration.layoutDirection == View.LAYOUT_DIRECTION_RTL)
                v.left else v.right
            if (event.rawX >= (end - v.compoundPaddingEnd)) {
                action.invoke()
                return@setOnTouchListener true
            }
        }
        return@setOnTouchListener false
    }
}

extension usage:

editText.onDrawableEndClick {
    // TODO clear action
    etSearch.setText("")
}

Android's support libarary has a SearchView class that does exactly this. (Not derrived from EditText though, so have to use a SearchView.OnQueryTextListener instead of a TextWatcher)

Search view with no text (and hint text "Search")

enter image description here

Use in XML like so:

  <android.support.v7.widget.SearchView
            android:id="@+id/searchView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:iconifiedByDefault="false"
            android:queryHint="@string/SearchHint"
            app:iconifiedByDefault="false"
            app:queryHint="@string/SearchHint" />

If you don't want to use custom views or special layouts, you can use 9-patch to make the (X) button .

Example: http://postimg.org/image/tssjmt97p/ (I don't have enough points to post images on StackOverflow)

The intersection of the right and bottom black pixels represent the content area. Anything outside of that area is padding. So to detect that the user clicked on the x you can set a OnTouchListener like so:

editText.setOnTouchListener(new View.OnTouchListener() {
    @Override
    public boolean onTouch(View view, MotionEvent motionEvent) {
        if (motionEvent.getAction() == MotionEvent.ACTION_UP){
            if (motionEvent.getX()>(view.getWidth()-view.getPaddingRight())){
                ((EditText)view).setText("");
            }
        }
        return false;
    }
});

According to your needs this solution can work better in some cases. I prefer to keep my xml less complicated. This also helps if you want to have an icon on the left, as you can simply include it in the 9 patch.


    <EditText
    android:id="@+id/idSearchEditText"
    android:layout_width="match_parent"
    android:layout_height="@dimen/dimen_40dp"
    android:drawableStart="@android:drawable/ic_menu_search"
    android:drawablePadding="8dp"
    android:ellipsize="start"
    android:gravity="center_vertical"
    android:hint="Search"
    android:imeOptions="actionSearch"
    android:inputType="text"
    android:paddingStart="16dp"
    android:paddingEnd="8dp"
/>

EditText mSearchEditText = findViewById(R.id.idSearchEditText);
mSearchEditText.addTextChangedListener(this);
mSearchEditText.setOnTouchListener(this);


@Override
public void afterTextChanged(Editable aEditable) {
    int clearIcon = android.R.drawable.ic_notification_clear_all;
    int searchIcon = android.R.drawable.ic_menu_search;
    if (aEditable == null || TextUtils.isEmpty(aEditable.toString())) {
        clearIcon = 0;
        searchIcon = android.R.drawable.ic_menu_search;
    } else {
        clearIcon = android.R.drawable.ic_notification_clear_all;
        searchIcon = 0;
    }
    Drawable leftDrawable =  null;
    if (searchIcon != 0) {
        leftDrawable = getResources().getDrawable(searchIcon);
    }
    Drawable rightDrawable = null;
    if (clearIcon != 0) {
        rightDrawable = getResources().getDrawable(clearIcon);
    }

    mSearchEditText.setCompoundDrawablesWithIntrinsicBounds(leftDrawable, null, rightDrawable, null);
}


@Override
public boolean onTouch(View aView, MotionEvent aEvent) {
    if (aEvent.getAction() == MotionEvent.ACTION_UP){
        if (aEvent.getX() > ( mSearchEditText.getWidth() - 
         mSearchEditText.getCompoundPaddingEnd())){
            mSearchEditText.setText("");
        }
    }
    return false;
}

Clear text:

"Text field with a clear text trailing icon."

If set, an icon is displayed when text is present and pressing it clears the input text.

    ...
    app:endIconMode="clear_text">
?
    ...
?
</com.google.android.material.textfield.TextInputLayout>

I leave it here:

material.io

Example
example