Setting Onclicklistener for the Drawable Right of an Edittext

Setting onClickListener for the Drawable right of an EditText

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;
}
}

});

Setting on click listener to TextInputEditText drawable Right/End android studio

Don't use android:drawableRight or android:drawableEnd in the TextInputEditText.

Instead you can use:

<com.google.android.material.textfield.TextInputLayout
...
app:endIconMode="custom"
app:endIconDrawable="@drawable/..."

and then use the endIconOnClickListener:

textInputLayout.setEndIconOnClickListener {
// Respond to end icon presses
}

How can I add OnClickListener to Drawable in EditText?

Drawables are non-interactive elements, so you cannont set a click listener on a drawable.
A simple solution would be putting an ImageView containing the "search" icon over the EditText and adding a right padding on the EditText so the text doesn't overlap with the icon.

<FrameLayout android:layout_width="wrap_content"
android:layout_height="wrap_content">
<EditText ...
android:paddingRight="..."
... />
<ImageView ...
android:src="@drawable/search"
android:layout_gravity="right|center_vertical"
... />
</FrameLayout>

Issue while implementing drawable right click event of edittext

XML code `

                    <EditText
android:id="@+id/et_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="12"
android:hint="Text"
android:singleLine="true" />

<ImageButton
android:id="@+id/ib_clear"
style="?android:buttonBarButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="-50dp"
android:layout_marginStart="-50dp"
android:src="@drawable/ic_cancel_black_24dp" />
</LinearLayout>`

you can change the visibility of the cross icon(image button) in Java code. you can add onclicklistener to image button for clickevent.

Do following to hide or display cross icon

 et_text.addTextChangedListener(new TextWatcher(){
public void afterTextChanged(Editable s) {}
public void beforeTextChanged(CharSequence s, int start, int count, int after){}
public void onTextChanged(CharSequence s, int start, int before, int count){if(et_text.getText().toString().length()>0){et_text.setVisibility(VIEW.VISIBLE);}else{et_text.setVisibility(VIEW.GONE);}
}});

Click on EditText's drawable right with Espresso

Had to develop this custom action and matcher to test our discard drawables on the right of some text fields,
discard edittext
this will click any drawable (left, top, right, bottom) of a TextView in an Espresso test.

Usage:

onView(withId(id)).perform(clickDrawables());

Method:

public static ViewAction clickDrawables()
{
return new ViewAction()
{
@Override
public Matcher<View> getConstraints()//must be a textview with drawables to do perform
{
return allOf(isAssignableFrom(TextView.class), new BoundedMatcher<View, TextView>(TextView.class)
{
@Override
protected boolean matchesSafely(final TextView tv)
{
if(tv.requestFocusFromTouch())//get fpocus so drawables become visible
for(Drawable d : tv.getCompoundDrawables())//if the textview has drawables then return a match
if(d != null)
return true;

return false;
}

@Override
public void describeTo(Description description)
{
description.appendText("has drawable");
}
});
}

@Override
public String getDescription()
{
return "click drawables";
}

@Override
public void perform(final UiController uiController, final View view)
{
TextView tv = (TextView)view;
if(tv != null && tv.requestFocusFromTouch())//get focus so drawables are visible
{
Drawable[] drawables = tv.getCompoundDrawables();

Rect tvLocation = new Rect();
tv.getHitRect(tvLocation);

Point[] tvBounds = new Point[4];//find textview bound locations
tvBounds[0] = new Point(tvLocation.left, tvLocation.centerY());
tvBounds[1] = new Point(tvLocation.centerX(), tvLocation.top);
tvBounds[2] = new Point(tvLocation.right, tvLocation.centerY());
tvBounds[3] = new Point(tvLocation.centerX(), tvLocation.bottom);

for(int location = 0; location < 4; location++)
if(drawables[location] != null)
{
Rect bounds = drawables[location].getBounds();
tvBounds[location].offset(bounds.width() / 2, bounds.height() / 2);//get drawable click location for left, top, right, bottom
if(tv.dispatchTouchEvent(MotionEvent.obtain(android.os.SystemClock.uptimeMillis(), android.os.SystemClock.uptimeMillis(), MotionEvent.ACTION_DOWN, tvBounds[location].x, tvBounds[location].y, 0)))
tv.dispatchTouchEvent(MotionEvent.obtain(android.os.SystemClock.uptimeMillis(), android.os.SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, tvBounds[location].x, tvBounds[location].y, 0));
}
}
}
};
}




This is a refinement I made to select a specific drawable to click:


Usage:

onView(withId(id)).perform(new ClickDrawableAction(ClickDrawableAction.Right));

Method:

public static class ClickDrawableAction implements ViewAction
{
public static final int Left = 0;
public static final int Top = 1;
public static final int Right = 2;
public static final int Bottom = 3;

@Location
private final int drawableLocation;

public ClickDrawableAction(@Location int drawableLocation)
{
this.drawableLocation = drawableLocation;
}

@Override
public Matcher<View> getConstraints()
{
return allOf(isAssignableFrom(TextView.class), new BoundedMatcher<View, TextView>(TextView.class)
{
@Override
protected boolean matchesSafely(final TextView tv)
{
//get focus so drawables are visible and if the textview has a drawable in the position then return a match
return tv.requestFocusFromTouch() && tv.getCompoundDrawables()[drawableLocation] != null;

}

@Override
public void describeTo(Description description)
{
description.appendText("has drawable");
}
});
}

@Override
public String getDescription()
{
return "click drawable ";
}

@Override
public void perform(final UiController uiController, final View view)
{
TextView tv = (TextView)view;//we matched
if(tv != null && tv.requestFocusFromTouch())//get focus so drawables are visible
{
//get the bounds of the drawable image
Rect drawableBounds = tv.getCompoundDrawables()[drawableLocation].getBounds();

//calculate the drawable click location for left, top, right, bottom
final Point[] clickPoint = new Point[4];
clickPoint[Left] = new Point(tv.getLeft() + (drawableBounds.width() / 2), (int)(tv.getPivotY() + (drawableBounds.height() / 2)));
clickPoint[Top] = new Point((int)(tv.getPivotX() + (drawableBounds.width() / 2)), tv.getTop() + (drawableBounds.height() / 2));
clickPoint[Right] = new Point(tv.getRight() + (drawableBounds.width() / 2), (int)(tv.getPivotY() + (drawableBounds.height() / 2)));
clickPoint[Bottom] = new Point((int)(tv.getPivotX() + (drawableBounds.width() / 2)), tv.getBottom() + (drawableBounds.height() / 2));

if(tv.dispatchTouchEvent(MotionEvent.obtain(android.os.SystemClock.uptimeMillis(), android.os.SystemClock.uptimeMillis(), MotionEvent.ACTION_DOWN, clickPoint[drawableLocation].x, clickPoint[drawableLocation].y, 0)))
tv.dispatchTouchEvent(MotionEvent.obtain(android.os.SystemClock.uptimeMillis(), android.os.SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, clickPoint[drawableLocation].x, clickPoint[drawableLocation].y, 0));
}
}

@IntDef({ Left, Top, Right, Bottom })
@Retention(RetentionPolicy.SOURCE)
public @interface Location{}
}


Related Topics



Leave a reply



Submit