Setting onClickListener for the Drawable right of an EditText

AndroidAndroid Edittext

Android Problem Overview


In my app I have a EditText with a search Icon on the right side. I used the code given below.

 <EditText
        android:id="@+id/search"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_margin="4dip"
        android:layout_weight="1"
        android:background="@drawable/textfield_search1"
        android:drawableLeft="@drawable/logo"
        android:drawableRight="@drawable/search_icon"
        android:hint="Search Anything..."
        android:padding="4dip"
        android:singleLine="true" />

I want to set the onClickListener for the search icon image assigned to the right drawable of EditText. How is it possible?

Android Solutions


Solution 1 - Android

Simple Solution, use methods that Android has already given, rather than reinventing wheeeeeeeeeel :-)

editComment.setOnTouchListener(new OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            final int DRAWABLE_LEFT = 0;
            final int DRAWABLE_TOP = 1;
            final int DRAWABLE_RIGHT = 2;
            final int DRAWABLE_BOTTOM = 3;

            if(event.getAction() == MotionEvent.ACTION_UP) {
                if(event.getRawX() >= (editComment.getRight() - editComment.getCompoundDrawables()[DRAWABLE_RIGHT].getBounds().width())) {
                    // your action here

                 return true;
                }
            }
            return false;
        }
    });

Solution 2 - Android

public class CustomEditText extends androidx.appcompat.widget.AppCompatEditText {

	private Drawable drawableRight;
	private Drawable drawableLeft;
	private Drawable drawableTop;
	private Drawable drawableBottom;

	int actionX, actionY;

	private DrawableClickListener clickListener;

	public CustomEditText (Context context, AttributeSet attrs) {
		super(context, attrs);
		// this Contructure required when you are using this view in xml
	}

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

	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);

	}

	@Override
	protected void onSizeChanged(int w, int h, int oldw, int oldh) {
		super.onSizeChanged(w, h, oldw, oldh);
	}

	@Override
	public void setCompoundDrawables(Drawable left, Drawable top,
			Drawable right, Drawable bottom) {
		if (left != null) {
			drawableLeft = left;
		}
		if (right != null) {
			drawableRight = right;
		}
		if (top != null) {
			drawableTop = top;
		}
		if (bottom != null) {
			drawableBottom = bottom;
		}
		super.setCompoundDrawables(left, top, right, bottom);
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		Rect bounds;
		if (event.getAction() == MotionEvent.ACTION_DOWN) {
			actionX = (int) event.getX();
			actionY = (int) event.getY();
			if (drawableBottom != null
					&& drawableBottom.getBounds().contains(actionX, actionY)) {
				clickListener.onClick(DrawablePosition.BOTTOM);
				return super.onTouchEvent(event);
			}

			if (drawableTop != null
					&& drawableTop.getBounds().contains(actionX, actionY)) {
				clickListener.onClick(DrawablePosition.TOP);
				return super.onTouchEvent(event);
			}

			// this works for left since container shares 0,0 origin with bounds
			if (drawableLeft != null) {
				bounds = null;
				bounds = drawableLeft.getBounds();

				int x, y;
				int extraTapArea = (int) (13 * getResources().getDisplayMetrics().density  + 0.5);

				x = actionX;
				y = actionY;

				if (!bounds.contains(actionX, actionY)) {
					/** Gives the +20 area for tapping. */
					x = (int) (actionX - extraTapArea);
					y = (int) (actionY - extraTapArea);

					if (x <= 0)
						x = actionX;
					if (y <= 0)
						y = actionY;

					/** Creates square from the smallest value */
					if (x < y) {
						y = x;
					}
				}

				if (bounds.contains(x, y) && clickListener != null) {
					clickListener
							.onClick(DrawableClickListener.DrawablePosition.LEFT);
					event.setAction(MotionEvent.ACTION_CANCEL);
					return false;

				}
			}

			if (drawableRight != null) {

				bounds = null;
				bounds = drawableRight.getBounds();

				int x, y;
				int extraTapArea = 13;

				/**
				 * IF USER CLICKS JUST OUT SIDE THE RECTANGLE OF THE DRAWABLE
				 * THAN ADD X AND SUBTRACT THE Y WITH SOME VALUE SO THAT AFTER
				 * CALCULATING X AND Y CO-ORDINATE LIES INTO THE DRAWBABLE
				 * BOUND. - this process help to increase the tappable area of
				 * the rectangle.
				 */
				x = (int) (actionX + extraTapArea);
				y = (int) (actionY - extraTapArea);

				/**Since this is right drawable subtract the value of x from the width 
				* of view. so that width - tappedarea will result in x co-ordinate in drawable bound. 
				*/
				x = getWidth() - x;
				
				 /*x can be negative if user taps at x co-ordinate just near the width.
				 * e.g views width = 300 and user taps 290. Then as per previous calculation
				 * 290 + 13 = 303. So subtract X from getWidth() will result in negative value.
				 * So to avoid this add the value previous added when x goes negative.
				 */
				 
				if(x <= 0){
					x += extraTapArea;
				}
				
				 /* If result after calculating for extra tappable area is negative.
				 * assign the original value so that after subtracting
				 * extratapping area value doesn't go into negative value.
				 */				  
				 
				if (y <= 0)
					y = actionY;				

				/**If drawble bounds contains the x and y points then move ahead.*/
				if (bounds.contains(x, y) && clickListener != null) {
					clickListener
							.onClick(DrawableClickListener.DrawablePosition.RIGHT);
					event.setAction(MotionEvent.ACTION_CANCEL);
					return false;
				}
				return super.onTouchEvent(event);
			}			

		}
		return super.onTouchEvent(event);
	}

	@Override
	protected void finalize() throws Throwable {
		drawableRight = null;
		drawableBottom = null;
		drawableLeft = null;
		drawableTop = null;
		super.finalize();
	}

	public void setDrawableClickListener(DrawableClickListener listener) {
		this.clickListener = listener;
	}

}

Also Create an Interface with

public interface DrawableClickListener {

	public static enum DrawablePosition { TOP, BOTTOM, LEFT, RIGHT };
	public void onClick(DrawablePosition target); 
	}

Still if u need any help, comment

Also set the drawableClickListener on the view in activity file.

editText.setDrawableClickListener(new DrawableClickListener() {
		
		 
		public void onClick(DrawablePosition target) {
			switch (target) {
			case LEFT:
				//Do something here
				break;

			default:
				break;
			}
		}
		
	});

Solution 3 - Android

This has been already answered but I tried a different way to make it simpler.

The idea is using putting an ImageButton on the right of EditText and having negative margin to it so that the EditText flows into the ImageButton making it look like the Button is in the EditText.

enter image description here

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <EditText
            android:id="@+id/editText"
            android:layout_weight="1"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:hint="Enter Pin"
            android:singleLine="true"
            android:textSize="25sp"
            android:paddingRight="60dp"
            />
        <ImageButton
            android:id="@+id/pastePin"
            android:layout_marginLeft="-60dp"
            style="?android:buttonBarButtonStyle"
            android:paddingBottom="5dp"
            android:src="@drawable/ic_action_paste"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    </LinearLayout>

Also, as shown above, you can use a paddingRight of similar width in the EditText if you don't want the text in it to be flown over the ImageButton.

I guessed margin size with the help of android-studio's layout designer and it looks similar across all screen sizes. Or else you can calculate the width of the ImageButton and set the margin programatically.

Solution 4 - Android

You don't have access to the right image as far my knowledge, unless you override the onTouch event. I suggest to use a RelativeLayout, with one editText and one imageView, and set OnClickListener over the image view as below:

<RelativeLayout
        android:id="@+id/rlSearch"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@android:drawable/edit_text"
        android:padding="5dip" >

        <EditText
            android:id="@+id/txtSearch"
            android:layout_width="match_parent"
            
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:layout_toLeftOf="@+id/imgSearch"
            android:background="#00000000"
            android:ems="10"/>

        <ImageView
            android:id="@+id/imgSearch"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentRight="true"
            android:layout_centerVertical="true"
            android:src="@drawable/btnsearch" />
    </RelativeLayout>

Solution 5 - Android

I know this is quite old, but I recently had to do something very similar, and came up with a much simpler solution.

It boils down to the following steps:

  1. Create an XML layout that contains the EditText and Image
  2. Subclass FrameLayout and inflate the XML layout
  3. Add code for the click listener and any other behavior you want... without having to worry about positions of the click or any other messy code.

See this post for the full example: https://stackoverflow.com/questions/3554377/handling-click-events-on-a-drawable-within-an-edittext/22945875#22945875

Solution 6 - Android

Please use below trick:

  • Create an image button with your icon and set its background color to be transparent.
  • Put the image button on the EditText
  • Implement the 'onclic'k listener of the button to execute your function

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionuser965071View Question on Stackoverflow
Solution 1 - AndroidAZ_View Answer on Stackoverflow
Solution 2 - AndroidHardik4560View Answer on Stackoverflow
Solution 3 - AndroidMeetMView Answer on Stackoverflow
Solution 4 - AndroidjeetView Answer on Stackoverflow
Solution 5 - AndroidJustinView Answer on Stackoverflow
Solution 6 - AndroidChiragView Answer on Stackoverflow