处理EditText中可绘制对象上的单击事件

我在EditText小部件中添加了文本右侧的图像,使用以下XML:

<EditText
android:id="@+id/txtsearch"
...
android:layout_gravity="center_vertical"
android:background="@layout/shape"
android:hint="Enter place,city,state"
android:drawableRight="@drawable/cross" />

但我想在点击嵌入图像时清除EditText。我该怎么做呢?

161511 次浏览

考虑以下几点。这不是最优雅的解决方案,但它是有效的,我刚刚测试过。

  1. 创建自定义的EditTextCustomEditText.java:

    import android.content.Context;
    import android.graphics.Rect;
    import android.graphics.drawable.Drawable;
    import android.util.AttributeSet;
    import android.view.MotionEvent;
    import android.widget.EditText;
    
    
    public class CustomEditText extends EditText
    {
    private Drawable dRight;
    private Rect rBounds;
    
    
    public CustomEditText(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    }
    public CustomEditText(Context context, AttributeSet attrs) {
    super(context, attrs);
    }
    public CustomEditText(Context context) {
    super(context);
    }
    
    
    @Override
    public void setCompoundDrawables(Drawable left, Drawable top,
    Drawable right, Drawable bottom)
    {
    if(right !=null)
    {
    dRight = right;
    }
    super.setCompoundDrawables(left, top, right, bottom);
    }
    
    
    @Override
    public boolean onTouchEvent(MotionEvent event)
    {
    
    
    if(event.getAction() == MotionEvent.ACTION_UP && dRight!=null)
    {
    rBounds = dRight.getBounds();
    final int x = (int)event.getX();
    final int y = (int)event.getY();
    //System.out.println("x:/y: "+x+"/"+y);
    //System.out.println("bounds: "+bounds.left+"/"+bounds.right+"/"+bounds.top+"/"+bounds.bottom);
    //check to make sure the touch event was within the bounds of the drawable
    if(x>=(this.getRight()-rBounds.width()) && x<=(this.getRight()-this.getPaddingRight())
    && y>=this.getPaddingTop() && y<=(this.getHeight()-this.getPaddingBottom()))
    {
    //System.out.println("touch");
    this.setText("");
    event.setAction(MotionEvent.ACTION_CANCEL);//use this to prevent the keyboard from coming up
    }
    }
    return super.onTouchEvent(event);
    }
    
    
    @Override
    protected void finalize() throws Throwable
    {
    dRight = null;
    rBounds = null;
    super.finalize();
    }
    }
    
  2. Change your layout XML to this (where com.example is your actual project package name):

    <com.example.CustomEditText
    android:id="@+id/txtsearch"
    …
    android:layout_gravity="center_vertical"
    android:background="@layout/shape"
    android:hint="Enter place,city,state"
    android:drawableRight="@drawable/cross"
    />
    
  3. Finally, add this (or something similar) to your activity:

    …
    CustomEditText et = (CustomEditText) this.findViewById(R.id.txtsearch);
    …
    

I might be a bit off with the calculation of the touch bounds for the nested drawable but you get the idea.

I hope this helps.

扩展了RyanM的想法,我创建了一个更灵活的版本,它支持所有可绘制的类型(上、下、左、右)。虽然下面的代码扩展了TextView,适应它的编辑文本只是交换“扩展TextView”与“扩展EditText”的情况。从XML实例化小部件与在RyanM的示例中相同,只是小部件名称不同。


import android.content.Context;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.TextView;


import com.example.DrawableClickListener.DrawablePosition;


public class ButtonTextView extends TextView {


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


private int     actionX, actionY;


private DrawableClickListener clickListener;


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


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


public ButtonTextView(Context context) {
super(context);
}


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


if (left != null) {
drawableLeft = left;
}


if (top != null) {
drawableTop = top;
}


if (bottom != null) {
drawableBottom = bottom;
}


super.setCompoundDrawables(left, top, right, bottom);
}


@Override
public boolean onTouchEvent(MotionEvent event) {


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


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


if (drawableRight != null && drawableRight.getBounds().contains(actionX, actionY)) {
clickListener.onClick(DrawablePosition.RIGHT);
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;
}}

DrawableClickListener就像这样简单:

public interface DrawableClickListener {


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

然后是实际的实现:

class example implements DrawableClickListener {
public void onClick(DrawablePosition target) {
switch (target) {
case LEFT:
doSomethingA();
break;


case RIGHT:
doSomethingB();
break;


case BOTTOM:
doSomethingC();
break;


case TOP:
doSomethingD();
break;


default:
break;
}
}}

注:如果你不设置监听器,触摸TextView将导致一个NullPointerException。您可能希望在代码中添加更多的偏执狂。

最后一个贡献对contains(x,y)的使用不会直接作用于getBounds()的结果(除了,巧合的是,当使用“左”可绘制对象时)。getBounds方法只提供Rect定义原点为0,0的可绘制项的点——因此,实际上你需要对原始文章进行数学计算,以确定在包含EditText的维度的上下文中,单击是否在可绘制项的区域,但将其更改为顶部、右侧、左侧等。或者,你也可以描述一个Rect,它的坐标实际上相对于它在EditText容器中的位置,并使用contains(),尽管最后你做的是同样的数学计算。

把它们结合起来,你就得到了一个相当完整的解决方案,我只添加了一个实例属性consumesEvent,它让API用户决定是否应该通过它的结果设置ACTION_CANCEL来传递click事件。

此外,我不明白为什么boundsactionXactionY值是实例属性,而不仅仅是堆栈上的本地属性。

下面是我在上面的基础上制作的实现的剪接图。它修复了正确使用事件需要返回false的问题。它增加了一个“模糊”因素。在我使用EditText字段中的语音控件图标的用例中,我发现很难单击,因此模糊增加了被认为是单击可绘制对象的有效边界。对我来说,15工作得很好。我只需要drawableRight,所以我没有把数学插入其他的,以节省一些空间,但你明白这个想法。

package com.example.android;


import android.content.Context;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.EditText;
import android.graphics.Rect;


import com.example.android.DrawableClickListener;


public class ClickableButtonEditText extends EditText {
public static final String LOG_TAG = "ClickableButtonEditText";


private Drawable drawableRight;
private Drawable drawableLeft;
private Drawable drawableTop;
private Drawable drawableBottom;
private boolean consumeEvent = false;
private int fuzz = 0;


private DrawableClickListener clickListener;


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


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


public ClickableButtonEditText(Context context) {
super(context);
}


public void consumeEvent() {
this.setConsumeEvent(true);
}


public void setConsumeEvent(boolean b) {
this.consumeEvent = b;
}


public void setFuzz(int z) {
this.fuzz = z;
}


public int getFuzz() {
return fuzz;
}


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


if (left != null) {
drawableLeft = left;
}
super.setCompoundDrawables(left, top, right, bottom);
}


@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
int x, y;
Rect bounds;
x = (int) event.getX();
y = (int) event.getY();
// this works for left since container shares 0,0 origin with bounds
if (drawableLeft != null) {
bounds = drawableLeft.getBounds();
if (bounds.contains(x - fuzz, y - fuzz)) {
clickListener.onClick(DrawableClickListener.DrawablePosition.LEFT);
if (consumeEvent) {
event.setAction(MotionEvent.ACTION_CANCEL);
return false;
}
}
} else if (drawableRight != null) {
bounds = drawableRight.getBounds();
if (x >= (this.getRight() - bounds.width() - fuzz) && x <= (this.getRight() - this.getPaddingRight() + fuzz)
&& y >= (this.getPaddingTop() - fuzz) && y <= (this.getHeight() - this.getPaddingBottom()) + fuzz) {


clickListener.onClick(DrawableClickListener.DrawablePosition.RIGHT);
if (consumeEvent) {
event.setAction(MotionEvent.ACTION_CANCEL);
return false;
}
}
} else if (drawableTop != null) {
// not impl reader exercise :)
} else if (drawableBottom != null) {
// not impl reader exercise :)
}
}


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

非常非常好,感谢所有参与讨论的人。因此,如果你不想处理扩展类带来的不便,你可以执行以下操作(仅为正确的可绘制对象实现)

this.keyword = (AutoCompleteTextView) findViewById(R.id.search);
this.keyword.setOnTouchListener(new RightDrawableOnTouchListener(keyword) {
@Override
public boolean onDrawableTouch(final MotionEvent event) {
return onClickSearch(keyword,event);
}
});


private boolean onClickSearch(final View view, MotionEvent event) {
// do something
event.setAction(MotionEvent.ACTION_CANCEL);
return false;
}

下面是基于@Mark的回答的基本侦听器实现

public abstract class RightDrawableOnTouchListener implements OnTouchListener {
Drawable drawable;
private int fuzz = 10;


/**
* @param keyword
*/
public RightDrawableOnTouchListener(TextView view) {
super();
final Drawable[] drawables = view.getCompoundDrawables();
if (drawables != null && drawables.length == 4)
this.drawable = drawables[2];
}


/*
* (non-Javadoc)
*
* @see android.view.View.OnTouchListener#onTouch(android.view.View, android.view.MotionEvent)
*/
@Override
public boolean onTouch(final View v, final MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN && drawable != null) {
final int x = (int) event.getX();
final int y = (int) event.getY();
final Rect bounds = drawable.getBounds();
if (x >= (v.getRight() - bounds.width() - fuzz) && x <= (v.getRight() - v.getPaddingRight() + fuzz)
&& y >= (v.getPaddingTop() - fuzz) && y <= (v.getHeight() - v.getPaddingBottom()) + fuzz) {
return onDrawableTouch(event);
}
}
return false;
}


public abstract boolean onDrawableTouch(final MotionEvent event);


}

我认为如果我们使用一些技巧会容易得多:)

    用你的图标创建一个图像按钮并设置它的背景 . color为透明的
  1. 将图像按钮放在EditText和右边
  2. 实现按钮的onclick监听器来执行您的命令 李函数< / >

完成

最好在编辑文本的右边有ImageButton,并给负布局边距与编辑文本重叠。在ImageButton上设置监听器并执行操作。

@Override
public boolean onTouch(View v, MotionEvent event) {


Drawable drawableObj = getResources().getDrawable(R.drawable.search_btn);
int drawableWidth = drawableObj.getIntrinsicWidth();


int x = (int) event.getX();
int y = (int) event.getY();


if (event != null && event.getAction() == MotionEvent.ACTION_UP) {
if (x >= (searchPanel_search.getWidth() - drawableWidth - searchPanel_search.getPaddingRight())
&& x <= (searchPanel_search.getWidth() - searchPanel_search.getPaddingRight())


&& y >= searchPanel_search.getPaddingTop() && y <= (searchPanel_search.getHeight() - searchPanel_search.getPaddingBottom())) {


getSearchData();
}


else {
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.showSoftInput(searchPanel_search, InputMethodManager.SHOW_FORCED);
}
}
return super.onTouchEvent(event);


}

实际上,您不需要扩展任何类。假设我有一个EditText editComment和一个drawableRight

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

我们getRawX(),因为我们想要得到触摸在屏幕上的实际位置,而不是相对于父。

要获得左侧点击

if(event.getRawX() <= (editComment.getCompoundDrawables()[DRAWABLE_LEFT].getBounds().width()))

我创建了一个有用的抽象类DrawableClickListener,它实现了OnTouchListener

除了DrawableClickListener类之外,我还创建了4个额外的抽象类,它们扩展了DrawableClickListener类,并处理了对正确象限的可绘制区域的单击。

  • LeftDrawableClickListener
  • TopDrawableClickListener
  • RightDrawableClickListener
  • BottomDrawableClickListener

考虑要点

需要考虑的一件事是,如果这样做,图像不会调整大小;因此,在放入res /可拉的文件夹之前,图像必须正确缩放。

如果你定义一个包含ImageViewTextViewLinearLayout,那么操纵显示图像的大小就容易得多。


activity_my.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >


<TextView
android:id="@+id/myTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="replace this with a variable"
android:textSize="30sp"
android:drawableLeft="@drawable/my_left_image"
android:drawableRight="@drawable/my_right_image"
android:drawablePadding="9dp" />


</RelativeLayout>

MyActivity.java

package com.company.project.core;


import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;


public class MyActivity extends Activity
{


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


final TextView myTextView = (TextView) this.findViewById( R.id.myTextView );
myTextView.setOnTouchListener( new DrawableClickListener.LeftDrawableClickListener(myTextView)
{
@Override
public boolean onDrawableClick()
{
// TODO : insert code to perform on clicking of the LEFT drawable image...


return true;
}
} );
myTextView.setOnTouchListener( new DrawableClickListener.RightDrawableClickListener(myTextView)
{
@Override
public boolean onDrawableClick()
{
// TODO : insert code to perform on clicking of the RIGHT drawable image...


return true;
}
} );
}


}

DrawableClickListener.java

package com.company.project.core;


import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.TextView;


/**
* This class can be used to define a listener for a compound drawable.
*
* @author Matthew Weiler
* */
public abstract class DrawableClickListener implements OnTouchListener
{


/* PUBLIC CONSTANTS */
/**
* This represents the left drawable.
* */
public static final int DRAWABLE_INDEX_LEFT = 0;
/**
* This represents the top drawable.
* */
public static final int DRAWABLE_INDEX_TOP = 1;
/**
* This represents the right drawable.
* */
public static final int DRAWABLE_INDEX_RIGHT = 2;
/**
* This represents the bottom drawable.
* */
public static final int DRAWABLE_INDEX_BOTTOM = 3;
/**
* This stores the default value to be used for the
* {@link DrawableClickListener#fuzz}.
* */
public static final int DEFAULT_FUZZ = 10;


/* PRIVATE VARIABLES */
/**
* This stores the number of pixels of &quot;fuzz&quot; that should be
* included to account for the size of a finger.
* */
private final int fuzz;
/**
* This will store a reference to the {@link Drawable}.
* */
private Drawable drawable = null;


/* CONSTRUCTORS */
/**
* This will create a new instance of a {@link DrawableClickListener}
* object.
*
* @param view
*            The {@link TextView} that this {@link DrawableClickListener}
*            is associated with.
* @param drawableIndex
*            The index of the drawable that this
*            {@link DrawableClickListener} pertains to.
*            <br />
*            <i>use one of the values:
*            <b>DrawableOnTouchListener.DRAWABLE_INDEX_*</b></i>
*/
public DrawableClickListener( final TextView view, final int drawableIndex )
{
this( view, drawableIndex, DrawableClickListener.DEFAULT_FUZZ );
}


/**
* This will create a new instance of a {@link DrawableClickListener}
* object.
*
* @param view
*            The {@link TextView} that this {@link DrawableClickListener}
*            is associated with.
* @param drawableIndex
*            The index of the drawable that this
*            {@link DrawableClickListener} pertains to.
*            <br />
*            <i>use one of the values:
*            <b>DrawableOnTouchListener.DRAWABLE_INDEX_*</b></i>
* @param fuzzOverride
*            The number of pixels of &quot;fuzz&quot; that should be
*            included to account for the size of a finger.
*/
public DrawableClickListener( final TextView view, final int drawableIndex, final int fuzz )
{
super();
this.fuzz = fuzz;
final Drawable[] drawables = view.getCompoundDrawables();
if ( drawables != null && drawables.length == 4 )
{
this.drawable = drawables[drawableIndex];
}
}


/* OVERRIDDEN PUBLIC METHODS */
@Override
public boolean onTouch( final View v, final MotionEvent event )
{
if ( event.getAction() == MotionEvent.ACTION_DOWN && drawable != null )
{
final int x = (int) event.getX();
final int y = (int) event.getY();
final Rect bounds = drawable.getBounds();
if ( this.isClickOnDrawable( x, y, v, bounds, this.fuzz ) )
{
return this.onDrawableClick();
}
}
return false;
}


/* PUBLIC METHODS */
/**
*
* */
public abstract boolean isClickOnDrawable( final int x, final int y, final View view, final Rect drawableBounds, final int fuzz );


/**
* This method will be fired when the drawable is touched/clicked.
*
* @return
*         <code>true</code> if the listener has consumed the event;
*         <code>false</code> otherwise.
* */
public abstract boolean onDrawableClick();


/* PUBLIC CLASSES */
/**
* This class can be used to define a listener for a <b>LEFT</b> compound
* drawable.
* */
public static abstract class LeftDrawableClickListener extends DrawableClickListener
{


/* CONSTRUCTORS */
/**
* This will create a new instance of a
* {@link LeftDrawableClickListener} object.
*
* @param view
*            The {@link TextView} that this
*            {@link LeftDrawableClickListener} is associated with.
*/
public LeftDrawableClickListener( final TextView view )
{
super( view, DrawableClickListener.DRAWABLE_INDEX_LEFT );
}


/**
* This will create a new instance of a
* {@link LeftDrawableClickListener} object.
*
* @param view
*            The {@link TextView} that this
*            {@link LeftDrawableClickListener} is associated with.
* @param fuzzOverride
*            The number of pixels of &quot;fuzz&quot; that should be
*            included to account for the size of a finger.
*/
public LeftDrawableClickListener( final TextView view, final int fuzz )
{
super( view, DrawableClickListener.DRAWABLE_INDEX_LEFT, fuzz );
}


/* PUBLIC METHODS */
public boolean isClickOnDrawable( final int x, final int y, final View view, final Rect drawableBounds, final int fuzz )
{
if ( x >= ( view.getPaddingLeft() - fuzz ) )
{
if ( x <= ( view.getPaddingLeft() + drawableBounds.width() + fuzz ) )
{
if ( y >= ( view.getPaddingTop() - fuzz ) )
{
if ( y <= ( view.getHeight() - view.getPaddingBottom() + fuzz ) )
{
return true;
}
}
}
}
return false;
}


}


/**
* This class can be used to define a listener for a <b>TOP</b> compound
* drawable.
* */
public static abstract class TopDrawableClickListener extends DrawableClickListener
{


/* CONSTRUCTORS */
/**
* This will create a new instance of a {@link TopDrawableClickListener}
* object.
*
* @param view
*            The {@link TextView} that this
*            {@link TopDrawableClickListener} is associated with.
*/
public TopDrawableClickListener( final TextView view )
{
super( view, DrawableClickListener.DRAWABLE_INDEX_TOP );
}


/**
* This will create a new instance of a {@link TopDrawableClickListener}
* object.
*
* @param view
*            The {@link TextView} that this
*            {@link TopDrawableClickListener} is associated with.
* @param fuzzOverride
*            The number of pixels of &quot;fuzz&quot; that should be
*            included to account for the size of a finger.
*/
public TopDrawableClickListener( final TextView view, final int fuzz )
{
super( view, DrawableClickListener.DRAWABLE_INDEX_TOP, fuzz );
}


/* PUBLIC METHODS */
public boolean isClickOnDrawable( final int x, final int y, final View view, final Rect drawableBounds, final int fuzz )
{
if ( x >= ( view.getPaddingLeft() - fuzz ) )
{
if ( x <= ( view.getWidth() - view.getPaddingRight() + fuzz ) )
{
if ( y >= ( view.getPaddingTop() - fuzz ) )
{
if ( y <= ( view.getPaddingTop() + drawableBounds.height() + fuzz ) )
{
return true;
}
}
}
}
return false;
}


}


/**
* This class can be used to define a listener for a <b>RIGHT</b> compound
* drawable.
* */
public static abstract class RightDrawableClickListener extends DrawableClickListener
{


/* CONSTRUCTORS */
/**
* This will create a new instance of a
* {@link RightDrawableClickListener} object.
*
* @param view
*            The {@link TextView} that this
*            {@link RightDrawableClickListener} is associated with.
*/
public RightDrawableClickListener( final TextView view )
{
super( view, DrawableClickListener.DRAWABLE_INDEX_RIGHT );
}


/**
* This will create a new instance of a
* {@link RightDrawableClickListener} object.
*
* @param view
*            The {@link TextView} that this
*            {@link RightDrawableClickListener} is associated with.
* @param fuzzOverride
*            The number of pixels of &quot;fuzz&quot; that should be
*            included to account for the size of a finger.
*/
public RightDrawableClickListener( final TextView view, final int fuzz )
{
super( view, DrawableClickListener.DRAWABLE_INDEX_RIGHT, fuzz );
}


/* PUBLIC METHODS */
public boolean isClickOnDrawable( final int x, final int y, final View view, final Rect drawableBounds, final int fuzz )
{
if ( x >= ( view.getWidth() - view.getPaddingRight() - drawableBounds.width() - fuzz ) )
{
if ( x <= ( view.getWidth() - view.getPaddingRight() + fuzz ) )
{
if ( y >= ( view.getPaddingTop() - fuzz ) )
{
if ( y <= ( view.getHeight() - view.getPaddingBottom() + fuzz ) )
{
return true;
}
}
}
}
return false;
}


}


/**
* This class can be used to define a listener for a <b>BOTTOM</b> compound
* drawable.
* */
public static abstract class BottomDrawableClickListener extends DrawableClickListener
{


/* CONSTRUCTORS */
/**
* This will create a new instance of a
* {@link BottomDrawableClickListener} object.
*
* @param view
*            The {@link TextView} that this
*            {@link BottomDrawableClickListener} is associated with.
*/
public BottomDrawableClickListener( final TextView view )
{
super( view, DrawableClickListener.DRAWABLE_INDEX_BOTTOM );
}


/**
* This will create a new instance of a
* {@link BottomDrawableClickListener} object.
*
* @param view
*            The {@link TextView} that this
*            {@link BottomDrawableClickListener} is associated with.
* @param fuzzOverride
*            The number of pixels of &quot;fuzz&quot; that should be
*            included to account for the size of a finger.
*/
public BottomDrawableClickListener( final TextView view, final int fuzz )
{
super( view, DrawableClickListener.DRAWABLE_INDEX_BOTTOM, fuzz );
}


/* PUBLIC METHODS */
public boolean isClickOnDrawable( final int x, final int y, final View view, final Rect drawableBounds, final int fuzz )
{
if ( x >= ( view.getPaddingLeft() - fuzz ) )
{
if ( x <= ( view.getWidth() - view.getPaddingRight() + fuzz ) )
{
if ( y >= ( view.getHeight() - view.getPaddingBottom() - drawableBounds.height() - fuzz ) )
{
if ( y <= ( view.getHeight() - view.getPaddingBottom() + fuzz ) )
{
return true;
}
}
}
}
return false;
}


}


}

我知道这很老了,但我最近不得不做一些类似的事情……在看到这有多难之后,我想到了一个更简单的解决方案:

  1. 创建一个包含EditText和Image的XML布局
  2. 子类framayout并扩展XML布局
  3. 为单击侦听器和任何其他您想要的行为添加代码

在我的例子中,我需要一个能够用按钮清除文本的EditText。我希望它看起来像SearchView,但由于一些原因,我不想使用这个类。下面的例子展示了我是如何完成这个任务的。尽管它与焦点变化无关,但原则是相同的,我认为发布实际的工作代码比将一个可能不完全按照我的意图工作的示例放在一起更有益:

下面是我的布局:clearle_edit_text .xml

<merge
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">


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


<!-- NOTE: Visibility cannot be set to "gone" or the padding won't get set properly in code -->
<ImageButton
android:id="@+id/edit_text_clear"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right|center_vertical"
android:background="@drawable/ic_cancel_x"
android:visibility="invisible"/>
</merge>

这里是膨胀布局的类:clearleedittext .java

public class ClearableEditText extends FrameLayout {
private boolean mPaddingSet = false;


/**
* Creates a new instance of this class.
* @param context The context used to create the instance
*/
public ClearableEditText (final Context context) {
this(context, null, 0);
}


/**
* Creates a new instance of this class.
* @param context The context used to create the instance
* @param attrs The attribute set used to customize this instance
*/
public ClearableEditText (final Context context, final AttributeSet attrs) {
this(context, attrs, 0);
}


/**
* Creates a new instance of this class.
* @param context The context used to create the instance
* @param attrs The attribute set used to customize this instance
* @param defStyle The default style to be applied to this instance
*/
public ClearableEditText (final Context context, final AttributeSet attrs, final int defStyle) {
super(context, attrs, defStyle);


final LayoutInflater inflater = LayoutInflater.from(context);
inflater.inflate(R.layout.clearable_edit_text, this, true);
}


@Override
protected void onFinishInflate () {
super.onFinishInflate();


final EditText editField = (EditText) findViewById(R.id.edit_text_field);
final ImageButton clearButton = (ImageButton) findViewById(R.id.edit_text_clear);


//Set text listener so we can show/hide the close button based on whether or not it has text
editField.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged (final CharSequence charSequence, final int i, final int i2, final int i3) {
//Do nothing here
}


@Override
public void onTextChanged (final CharSequence charSequence, final int i, final int i2, final int i3) {
//Do nothing here
}


@Override
public void afterTextChanged (final Editable editable) {
clearButton.setVisibility(editable.length() > 0 ? View.VISIBLE : View.INVISIBLE);
}
});


//Set the click listener for the button to clear the text. The act of clearing the text will hide this button because of the
//text listener
clearButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick (final View view) {
editField.setText("");
}
});
}


@Override
protected void onLayout (final boolean changed, final int left, final int top, final int right, final int bottom) {
super.onLayout(changed, left, top, right, bottom);


//Set padding here in the code so the text doesn't run into the close button. This could be done in the XML layout, but then if
//the size of the image changes then we constantly need to tweak the padding when the image changes. This way it happens automatically
if (!mPaddingSet) {
final EditText editField = (EditText) findViewById(R.id.edit_text_field);
final ImageButton clearButton = (ImageButton) findViewById(R.id.edit_text_clear);


editField.setPadding(editField.getPaddingLeft(), editField.getPaddingTop(), clearButton.getWidth(), editField.getPaddingBottom());
mPaddingSet = true;
}
}
}

为了使这个答案更符合问题,应该采取以下步骤:

  1. 将可绘制资源更改为您想要的任何资源…在我的情况下,它是一个灰色的X
  2. 添加一个焦点更改监听器到编辑文本…

这是我的简单解决方案,只是把ImageButton放在EditText上:

<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">


<EditText android:id="@+id/editTextName"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:imeOptions="actionSearch"
android:inputType="text"/>


<ImageButton android:id="@+id/imageViewSearch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_action_search"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"/>


</RelativeLayout>
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="5dp" >


<EditText
android:id="@+id/edt_status_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:background="@drawable/txt_box_blank"
android:ems="10"
android:hint="@string/statusnote"
android:paddingLeft="5dp"
android:paddingRight="10dp"
android:textColor="@android:color/black" />


<Button
android:id="@+id/note_del"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:layout_marginRight="1dp"
android:layout_marginTop="5dp"
android:background="@android:drawable/ic_delete" />
</FrameLayout>
这很简单。 假设你在你的编辑文本'txtsearch'的左边有一个可绘制的图形。

EditText txtsearch = (EditText) findViewById(R.id.txtsearch);
txtsearch.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_UP) {
if(event.getRawX() <= txtsearch.getTotalPaddingLeft()) {
// your action for drawable click event


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

如果你想要右绘图,将If语句更改为:

if(event.getRawX() >= txtsearch.getRight() - txtsearch.getTotalPaddingRight())

类似地,您可以为所有复合提款执行此操作。

txtsearch.getTotalPaddingTop()
txtsearch.getTotalPaddingBottom()

此方法调用返回该边的所有填充,包括任何可绘制对象。你可以使用这甚至为TextView,按钮等。

点击在这里从android开发者网站参考。

这对我很有用,

mEditTextSearch.addTextChangedListener(new TextWatcher() {


@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if(s.length()>0){
mEditTextSearch.setCompoundDrawablesWithIntrinsicBounds(null, null, getResources().getDrawable(android.R.drawable.ic_delete), null);
}else{
mEditTextSearch.setCompoundDrawablesWithIntrinsicBounds(null, null, getResources().getDrawable(R.drawable.abc_ic_search), null);
}
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void afterTextChanged(Editable s) {
}
});
mEditTextSearch.setOnTouchListener(new OnTouchListener() {
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouch(View v, MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_UP) {
if(mEditTextSearch.getCompoundDrawables()[2]!=null){
if(event.getX() >= (mEditTextSearch.getRight()- mEditTextSearch.getLeft() - mEditTextSearch.getCompoundDrawables()[2].getBounds().width())) {
mEditTextSearch.setText("");
}
}
}
return false;
}
});

如果drawable在左边,这对你有帮助。(适用于使用RTL布局的用户)

 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() <= (searchbox.getLeft() + searchbox.getCompoundDrawables()[DRAWABLE_LEFT].getBounds().width())) {
// your action here


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

用于左侧可绘制的单击侦听器

txt.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
final int DRAWABLE_LEFT = 0;


if (event.getAction() == MotionEvent.ACTION_UP) {
if (event.getRawX() <= (txt
.getCompoundDrawables()[DRAWABLE_LEFT].getBounds().width() +
txt.getPaddingLeft() +
txt.getLeft())) {


//TODO do code here
}
return true;
}
}
return false;
}
});

这一切都很棒,但为什么不让它变得更简单呢?

不久前我也遇到过这种情况……和android touchlistener工作得很好,但在使用上有限制..我找到了另一个解决方案,我希望能帮助你:

    <LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/zero_row">
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="match_parent">
<ProgressBar
android:id="@+id/loadingProgressBar"
android:layout_gravity="center"
android:layout_width="28dp"
android:layout_height="28dp" />
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:background="@drawable/edittext_round_corners"
android:layout_height="match_parent"
android:layout_marginLeft="5dp">
<ImageView
android:layout_width="28dp"
android:layout_height="28dp"
app:srcCompat="@android:drawable/ic_menu_search"
android:id="@+id/imageView2"
android:layout_weight="0.15"
android:layout_gravity="center|right"
android:onClick="OnDatabaseSearchEvent" />
<EditText
android:minHeight="40dp"
android:layout_marginLeft="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/edittext_round_corners"
android:inputType="textPersonName"
android:hint="Search.."
android:textColorHint="@color/AndroidWhite"
android:textColor="@color/AndroidWhite"
android:ems="10"
android:id="@+id/e_d_search"
android:textCursorDrawable="@color/AndroidWhite"
android:layout_weight="1" />
<ImageView
android:layout_width="28dp"
android:layout_height="28dp"
app:srcCompat="@drawable/ic_oculi_remove2"
android:id="@+id/imageView3"
android:layout_gravity="center|left"
android:layout_weight="0.15"
android:onClick="onSearchEditTextCancel" />
</LinearLayout>


<!--android:drawableLeft="@android:drawable/ic_menu_search"-->
<!--android:drawableRight="@drawable/ic_oculi_remove2"-->


</LinearLayout>


</LinearLayout>

enter image description here 现在您可以创建ImageClick侦听器或事件,并对文本做任何您想做的事情。这个edittext_round_corners.xml文件

<item android:state_pressed="false" android:state_focused="false">
<shape>
<gradient
android:centerY="0.2"
android:startColor="@color/colorAccent"
android:centerColor="@color/colorAccent"
android:endColor="@color/colorAccent"
android:angle="270"
/>
<stroke
android:width="0.7dp"
android:color="@color/colorAccent" />
<corners
android:radius="5dp" />
</shape>
</item>

我想建议一种方法绘制左侧!

txtsearch.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent event) {
final int DRAWABLE_LEFT = 0;
int start=txtsearch.getSelectionStart();
int end=txtsearch.getSelectionEnd();
if(event.getAction() == MotionEvent.ACTION_UP) {
if(event.getRawX() <= (txtsearch.getLeft() + txtsearch.getCompoundDrawables()[DRAWABLE_LEFT].getBounds().width())) {
//Do your action here
return true;
}


}
return false;
}
});
}

复合绘图不应该是可点击的。 在水平LinearLayout中使用单独的视图并在它们上使用单击处理程序会更干净。< / p >

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:background="@color/white"
android:layout_marginLeft="20dp"
android:layout_marginStart="20dp"
android:layout_marginRight="20dp"
android:layout_marginEnd="20dp"
android:layout_gravity="center_horizontal"
android:orientation="horizontal"
android:translationZ="4dp">


<ImageView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="@color/white"
android:minWidth="40dp"
android:scaleType="center"
app:srcCompat="@drawable/ic_search_map"/>


<android.support.design.widget.TextInputEditText
android:id="@+id/search_edit"
style="@style/EditText.Registration.Map"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:hint="@string/hint_location_search"
android:imeOptions="actionSearch"
android:inputType="textPostalAddress"
android:maxLines="1"
android:minHeight="40dp" />


<ImageView
android:id="@+id/location_gps_refresh"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="@color/white"
android:minWidth="40dp"
android:scaleType="center"
app:srcCompat="@drawable/selector_ic_gps"/>
</LinearLayout>

我在Mono中实现了@aristo_sh answer。Droid (Xamarin)因为它是一个委托匿名方法你不能返回true或false你必须取e。event。handled。我还隐藏了点击键盘

editText.Touch += (sender, e) => {
e.Handled = false;
if (e.Event.Action == MotionEventActions.Up)
{
if (e.Event.RawX >= (bibEditText.Right - (bibEditText.GetCompoundDrawables()[2]).Bounds.Width()))
{
SearchRunner();
InputMethodManager manager = (InputMethodManager)GetSystemService(InputMethodService);
manager.HideSoftInputFromWindow(editText.WindowToken, 0);
e.Handled = true;
}
}
};

只需复制粘贴下面的代码,它就能做到这一点。

editMsg.setOnTouchListener(new View.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() >= (editMsg.getRight() - editMsg.getCompoundDrawables()[DRAWABLE_RIGHT].getBounds().width())) {
// your action here


Toast.makeText(ChatActivity.this, "Message Sent", Toast.LENGTH_SHORT).show();
return true;
}
}
return false;
}
});

分享我的处理TextView复合可绘制的点击和触摸事件的通用解决方案。

首先,我们需要一个触摸事件处理程序:

/**
* Handles compound drawable touch events.
* Will intercept every event that happened inside (calculated) compound drawable bounds, extended by fuzz.
* @see TextView#getCompoundDrawables()
* @see TextView#setCompoundDrawablesRelativeWithIntrinsicBounds(int, int, int, int)
*/
public abstract class CompoundDrawableTouchListener implements View.OnTouchListener {


private final String LOG_TAG = "CmpDrawableTouch";


private final int fuzz;


public static final int LEFT = 0;
public static final int TOP = 1;
public static final int RIGHT = 2;
public static final int BOTTOM = 3;
private static final int[] DRAWABLE_INDEXES = {LEFT, TOP, RIGHT, BOTTOM};


/**
* Default constructor
*/
public CompoundDrawableTouchListener() {
this(0);
}


/**
* Constructor with fuzz
* @param fuzz desired fuzz in px
*/
public CompoundDrawableTouchListener(int fuzz) {
this.fuzz = fuzz;
}


@Override
public boolean onTouch(View view, MotionEvent event) {
if (!(view instanceof TextView)) {
Log.e(LOG_TAG, "attached view is not instance of TextView");
return false;
}


TextView textView = (TextView) view;
Drawable[] drawables = textView.getCompoundDrawables();
int x = (int) event.getX();
int y = (int) event.getY();


for (int i : DRAWABLE_INDEXES) {
if (drawables[i] == null) continue;
Rect bounds = getRelativeBounds(i, drawables[i], textView);
Rect fuzzedBounds = addFuzz(bounds);


if (fuzzedBounds.contains(x, y)) {
MotionEvent relativeEvent = MotionEvent.obtain(
event.getDownTime(),
event.getEventTime(),
event.getAction(),
event.getX() - bounds.left,
event.getY() - bounds.top,
event.getMetaState());
return onDrawableTouch(view, i, bounds, relativeEvent);
}
}


return false;
}


/**
* Calculates compound drawable bounds relative to wrapping view
* @param index compound drawable index
* @param drawable the drawable
* @param view wrapping view
* @return {@link Rect} with relative bounds
*/
private Rect getRelativeBounds(int index, @NonNull Drawable drawable, View view) {
Rect drawableBounds = drawable.getBounds();
Rect bounds = new Rect();


switch (index) {
case LEFT:
bounds.offsetTo(view.getPaddingLeft(),
view.getHeight() / 2 - bounds.height() / 2);
break;


case TOP:
bounds.offsetTo(view.getWidth() / 2 - bounds.width() / 2,
view.getPaddingTop());
break;


case RIGHT:
bounds.offsetTo(view.getWidth() - view.getPaddingRight() - bounds.width(),
view.getHeight() / 2 - bounds.height() / 2);
break;


case BOTTOM:
bounds.offsetTo(view.getWidth() / 2 - bounds.width() / 2,
view.getHeight() - view.getPaddingBottom() - bounds.height());
break;
}


return bounds;
}


/**
* Expands {@link Rect} by given value in every direction relative to its center
* @param source given {@link Rect}
* @return result {@link Rect}
*/
private Rect addFuzz(Rect source) {
Rect result = new Rect();
result.left = source.left - fuzz;
result.right = source.right + fuzz;
result.top = source.top - fuzz;
result.bottom = source.bottom + fuzz;
return result;
}


/**
* Compound drawable touch-event handler
* @param v wrapping view
* @param drawableIndex index of compound drawable which recicved the event
* @param drawableBounds {@link Rect} with compound drawable bounds relative to wrapping view.
* Fuzz not included
* @param event event with coordinated relative to wrapping view - i.e. within {@code drawableBounds}.
* If using fuzz, may return negative coordinates.
*/
protected abstract boolean onDrawableTouch(View v, int drawableIndex, Rect drawableBounds, MotionEvent event);
}

现在你可以处理任何触摸事件任何复合drawable的任何TextView你喜欢这样:

textView1.setOnTouchListener(new CompoundDrawableTouchListener() {
@Override
protected void onDrawableTouch(View v, int drawableIndex, Rect drawableBounds, MotionEvent event) {
switch(v.getId()) {
case R.id.textView1:
switch(drawableIndex) {
case CompoundDrawableTouchListener.RIGHT:
doStuff();
break;
}
break;
}
}
});

只对点击感兴趣?只需通过MotionEvent动作过滤:

/**
* Handles compound drawable click events.
* @see TextView#getCompoundDrawables()
* @see TextView#setCompoundDrawablesRelativeWithIntrinsicBounds(int, int, int, int)
* @see CompoundDrawableTouchListener
*/
public abstract class CompoundDrawableClickListener extends CompoundDrawableTouchListener {


/**
* Default constructor
*/
public CompoundDrawableClickListener() {
super();
}


/**
* Constructor with fuzz
* @param fuzz desired fuzz in px
*/
public CompoundDrawableClickListener(int fuzz) {
super(fuzz);
}


@Override
protected void onDrawableTouch(View v, int drawableIndex, Rect drawableBounds, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_UP) onDrawableClick(v, drawableIndex);
return true;
}


/**
* Compound drawable touch-event handler
* @param v wrapping view
* @param drawableIndex index of compound drawable which recicved the event
*/
protected abstract void onDrawableClick(View v, int drawableIndex);
}

同样,我们可以很容易地处理点击任何复合drawable的任何TextView:

textView1.setOnTouchListener(new CompoundDrawableClickListener() {
@Override
protected void onDrawableClick(View v, int drawableIndex) {
switch(v.getId()) {
case R.id.textView1:
switch(drawableIndex) {
case CompoundDrawableTouchListener.RIGHT:
doStuff();
break;
}
break;
}
}
});

希望你和我一样喜欢。如果有任何变化,我将尝试在这里和相关的依据中保持更新。

我创建了一个简单的自定义触摸侦听器类,而不是自定义EditText

public class MyTouchListener implements View.OnTouchListener {
private EditText editText;


public MyTouchListener(EditText editText) {
this.editText = editText;


setupDrawable(this.editText);
}


private void setupDrawable(final EditText editText) {
editText.addTextChangedListener(new TextWatcher() {
@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)
editText.setCompoundDrawablesWithIntrinsicBounds(0,0, R.drawable.clearicon,0);
else
editText.setCompoundDrawablesWithIntrinsicBounds(0,0, 0,0);


}


@Override
public void afterTextChanged(Editable s) {


}
});
}


@Override
public boolean onTouch(View v, MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_UP) {
if(editText.getCompoundDrawables()[2]!=null){
if(event.getX() >= (editText.getRight()- editText.getLeft() - editText.getCompoundDrawables()[2].getBounds().width())) {
editText.setText("");
}
}
}
return false;


}

当EditText为空白时,将没有可绘制对象。绘图将显示我们开始编辑以清除EditText的时间。

你可以设置触摸监听器

mEditText。setOnTouchListener(新MyTouchListener (mEditText));

对于任何不想实现可怕的点击处理的人。你可以用RelativeLayout实现同样的效果。有了它,你甚至可以自由处理可绘制对象的定位。

  <RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">


<android.support.design.widget.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">


<android.support.design.widget.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
</android.support.design.widget.TextInputLayout>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerInParent="true"
android:src="@drawable/ic_undo"/>
</RelativeLayout>

ImageView的位置将与你使用drawableEnd的位置相同-加上你不需要所有的触摸侦听器处理。只是一个ImageView的点击监听器,你就可以开始了。

这对我有用:)希望这对你也有帮助

edit_account_name.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
if (event.getRawX() >= (edit_account_name.getRight())) {
//clicked
return true;
}
}
return false;
}
});

我见过几个解决方案,但没有一个能说服我。要么非常复杂,要么太简单(不可重用)。

这是我目前最喜欢的方法:

mEditText.setOnTouchListener(
new OnEditTextRightDrawableTouchListener(mEditText) {
@Override
public void OnDrawableClick() {
// The right drawable was clicked. Your action goes here.
}
});

这是可重复使用的触摸监听器:

import android.graphics.drawable.Drawable;
import android.support.annotation.NonNull;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.EditText;


public abstract class OnEditTextRightDrawableTouchListener implements OnTouchListener {


private final EditText mEditText;


public OnEditTextRightDrawableTouchListener(@NonNull final EditText editText) {
mEditText = editText;
}


@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
if (motionEvent.getAction() == MotionEvent.ACTION_UP) {
final int DRAWABLE_RIGHT_POSITION = 2;
final Drawable drawable = mEditText.getCompoundDrawables()[DRAWABLE_RIGHT_POSITION];
if (drawable != null) {
final float touchEventX = motionEvent.getX();
final int touchAreaRight = mEditText.getRight();
final int touchAreaLeft = touchAreaRight - drawable.getBounds().width();
if (touchEventX >= touchAreaLeft && touchEventX <= touchAreaRight) {
view.performClick();
OnDrawableClick();
}
return true;
}
}
return false;
}


public abstract void OnDrawableClick();
}

你可以在这里看Gist

    final TextView mTvTitle = (TextView)findViewById(R.id.tvTitle1);


mTvTitle.setOnTouchListener(new View.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() <= (mTvTitle.getCompoundDrawables()[DRAWABLE_LEFT].getBounds().width()))  {
// your action here
Intent intent = new Intent(DeAddExpences.this,DeHomeActivity.class);
startActivity(intent);
return true;
}
}
return true;
}
});

按照下面的代码绘制右,左,上,下点击:

edittextview_confirmpassword.setOnTouchListener(new View.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() >= (edittextview_confirmpassword.getRight() - edittextview_confirmpassword.getCompoundDrawables()[DRAWABLE_RIGHT].getBounds().width())) {
// your action here                    edittextview_confirmpassword.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
return true;
}
}else{
edittextview_confirmpassword.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);


}
return false;
}
});

上述解决方案有效,但也有副作用。如果你有一个EditText和右drawable

enter image description here

你会得到一个粘贴按钮后,每次点击绘制。看到如何禁用粘贴在onClickListener的绘图权的一个EditText Android(内部图标EditText)

这么多的解决方案,但没有一个适合我,当我有两个字段在一行。 这是添加清除按钮编辑文本的解决方案,在我有两个字段或一行中的一个字段的情况下为我工作。

@SuppressLint("PrivateResource")
fun <T : EditText> T.withClear(): T {
addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(editable: Editable) {
setCompoundDrawablesWithIntrinsicBounds(0, 0,
if (editable.isNotEmpty()) abc_ic_clear_material else 0, 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 { _, event ->
if (event.action == ACTION_UP && event.x >= (right - this.compoundPaddingRight)) {
setText("")
return@setOnTouchListener true
}
false
}
return this
}

我使用了一个简短的解决方案,甚至适用于对话的片段。

enter image description here

            //The listener of a drawableEnd button for clear a TextInputEditText
textValue.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_UP) {
final TextView textView = (TextView)v;
if(event.getX() >= textView.getWidth() - textView.getCompoundPaddingEnd()) {
textView.setText(""); //Clear a view, example: EditText or TextView
return true;
}
}
return false;
}
});

我是这样做的

            <RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">


<android.support.design.widget.TextInputLayout
android:id="@+id/til_text"


android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:textColorHint="@color/colorSilver">


<android.support.design.widget.TextInputEditText
android:id="@+id/tiet_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="top|left"
android:hint="@string/rep_hint"
android:inputType="textMultiLine"
android:maxLines="3"
android:drawableEnd="@drawable/ic_attach_photo"
android:drawablePadding="5dp"
android:textColor="@color/colorPrimaryText"
android:textColorHint="@color/colorSilver"
/>


</android.support.design.widget.TextInputLayout>


<View
android:id="@+id/right_button"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_centerVertical="true"
android:layout_alignParentEnd="true"
android:layout_marginEnd="12dp"
android:background="@color/clear" />
</RelativeLayout>

Kotlin是一种很棒的语言,每个类都可以使用新方法进行扩展。让我们为EditText类介绍一个新方法,它将捕捉点击到右绘图。

fun EditText.onRightDrawableClicked(onClicked: (view: EditText) -> Unit) {
this.setOnTouchListener { v, event ->
var hasConsumed = false
if (v is EditText) {
if (event.x >= v.width - v.totalPaddingRight) {
if (event.action == MotionEvent.ACTION_UP) {
onClicked(this)
}
hasConsumed = true
}
}
hasConsumed
}
}

你可以看到它以回调函数作为参数,当用户单击右可绘制时调用。

val username = findViewById<EditText>(R.id.username_text)
username.onRightDrawableClicked {
it.text.clear()
}

使用可扩展的textview缓冲区可能是一个解决方案。看看这个简短而切中要害的教程:首先,点击事件要容易得多

https://android-designing.blogspot.com/2017/01/spannable-textview-with-image-clickable.html?m=1

以前的解决方案都没有为我工作在Xamarin的安卓。我能够得到正确的绘制点击监听器工作使用以下:

创建以下OnEditTextTouch事件监听器:

  private void OnEditTextTouch(object sender, View.TouchEventArgs e)
{
var rightDrawable = _autoCompleteTextViewSearch.GetCompoundDrawables()[2];


if (rightDrawable == null || e.Event.Action != MotionEventActions.Up)
{
e.Handled = false;


return;
}


if (e.Event.GetX() >= _autoCompleteTextViewSearch.Width - _autoCompleteTextViewSearch.TotalPaddingRight)
{
// Invoke your desired action here.


e.Handled = true;
}


// Forward the event along to the sender (crucial for default behaviour)
(sender as AutoCompleteTextView)?.OnTouchEvent(e.Event);
}

订阅Touch事件:

_autoCompleteTextViewSearch.Touch += OnEditTextTouch;

我想这是一个很好的方法,由Hardik4560推荐,

https://stackoverflow.com/a/13135554/7184172 < a href = " https://stackoverflow.com/a/13135554/7184172 " > < / >

我已经在Kotlin中实现

edPassword.setOnTouchListener { _, event ->
val DRAWABLE_RIGHT = 2
val DRAWABLE_LEFT = 0
val DRAWABLE_TOP = 1
val DRAWABLE_BOTTOM = 3
if (event.action == MotionEvent.ACTION_UP) {
if (event.rawX >= (edPassword.right - edPassword.compoundDrawables[DRAWABLE_RIGHT].bounds.width())) {
edPassword.setText("")
true
}
}
false
}

//单击右图标

enter image description here

editText.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
final int DRAWABLE_RIGHT = 2;


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


Toast.makeText(getActivity(), "Right icon click", Toast.LENGTH_SHORT).show();


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

我已经采取了@AZ_的解决方案,并将其转换为kotlin扩展函数:

所以在代码中复制这个:

@SuppressLint("ClickableViewAccessibility")
fun EditText.setDrawableRightTouch(setClickListener: () -> Unit) {
this.setOnTouchListener(View.OnTouchListener { _, event ->
val DRAWABLE_LEFT = 0
val DRAWABLE_TOP = 1
val DRAWABLE_RIGHT = 2
val DRAWABLE_BOTTOM = 3
if (event.action == MotionEvent.ACTION_UP) {
if (event.rawX >= this.right - this.compoundDrawables[DRAWABLE_RIGHT].bounds.width()
) {
setClickListener()
return@OnTouchListener true
}
}
false
})
}

你可以在你的EditText上调用setDrawableRightTouch函数来使用它:

yourEditText.setDrawableRightTouch {
//your code
}

上述问题的一个可能的解决方案是使用android的新材料组件TextInputLayout

<com.google.android.material.textfield.TextInputLayout
android:id="@+id/searchInput"
style="@style/Widget.App.TextInputLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/search"
app:endIconMode="custom"
app:endIconContentDescription="Search"
app:endIconDrawable="@drawable/ic_search">


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


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

在这里,TextInputLayout属性endIconMode设置后,将一个按钮放置在所附EditText的末尾。

另外,app:endIconMode = "custom"允许自定义图标的点击功能

最后,为了监听结束图标单击,调用外围TextInputLayout组件上的setEndIconClickListener ()

有更优雅的方式:
不要在TextInputEditText.

. c中使用android:drawableRightandroid:drawableEnd

相反,你可以用:

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

然后使用endIconOnClickListener:

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

来源:https://stackoverflow.com/a/65940540/13545849