在EditText中处理drawable上的click事件

我已经使用以下XML在EditText小部件中添加了文本的图像权限:

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

但是我想在点击embedded图像时清除EditText 。 我该怎么做?

其实你不需要延长任何课程。 比方说,我有一个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())) 

非常非常好,感谢所有参与讨论的人。 所以,如果你不想处理扩展类的不便,​​你可以做以下的事情(只适用于右边的drawable)

 this.keyword = (AutoCompleteTextView) findViewById(R.id.search); this.keyword.setOnTouchListener(new RightDrawableOnTouchListener(keyword) { @Override public boolean onDrawableTouch(final MotionEvent event) { return onClickSearch(keyword); } }); private boolean onClickSearch(final View view) { // 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); } 

考虑以下几点。 这不是最优雅的解决scheme,但它的工作原理,我只是testing它。

  1. 创build一个定制的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. 将您的布​​局XML更改为此(其中com.example是您的实际项目包名称):

     <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. 最后,将这个(或类似的)添加到您的活动中:

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

我可能会对嵌套drawable的触摸边界进行计算,但你明白了。

我希望这有帮助。

使用contains(x,y)最后一个贡献将不会直接影响getBounds()的结果(除非巧合,当使用“left”drawable时)。 getBounds方法只提供以0,0原点标准化的可绘制项目的Rect定义点 – 所以,实际上你需要做原始文章的math来确定点击是否在上下文的drawable区域包含EditText的尺寸,但改变它的顶部,右侧,左侧等。另外,你可以描述一个实际上坐标相对于其在EditText容器中的位置的Rect ,并使用contains() ,尽pipe最后你正在做同样的math。

把它们结合起来,给你提供了一个非常完整的解决scheme,我只添加了一个实例属性consumesEvent ,它允许API用户通过使用结果设置ACTION_CANCEL来决定是否传递click事件。

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

这里是基于上面我所做的一个实现的切口。 它修复了正确使用事件的问题,您需要返回false。 它增加了一个“模糊”因素。 在我使用EditText字段中的Voice控件图标的情况下,我发现很难点击,所以模糊会增加被视为点击drawable的有效范围。 对我来说15工作得很好。 我只需要drawableRight所以我没有把math插入其他人,以节省一些空间,但你看到的想法。

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

我创build了一个实现OnTouchListener的有用的抽象类DrawableClickListener

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

  • LeftDrawableClickListener
  • TopDrawableClickListener
  • RightDrawableClickListener
  • BottomDrawableClickListener

要考虑的一点

有一件事要考虑的是,如果这样做的话,图像不会resize; 因此图像必须在放入res / drawable文件夹之前正确缩放。

如果您定义了一个包含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; } } } 

它非常简单。 假设你在EditText的'txtsearch'的左边有一个drawable。 以下将做的伎俩。

 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,Button等

点击这里从Android开发人员网站的参考。

如果我们使用一些技巧,我认为它更容易:)

  1. 用你的图标创build一个图像button ,并将其背景色设置为透明
  2. 将图像button放在EditText上,右边放置图像button
  3. 实现button的onclick监听器来执行你的function

完成

由RyanM扩展的想法我创build了一个更灵活的版本,它支持所有可绘制的types(顶部,底部,左,右)。 虽然下面的代码扩展了TextView,但将它改写为EditText只是将“extends TextView”与“extends 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; } }} 

ps:如果你没有设置监听器,触摸TextView将导致NullPointerException。 你可能想在代码中增加一些偏执狂。

它为我工作,

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

如果在左边是可绘制的,这会帮助你。 (对于那些使用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; } }); 

我知道这是相当古老的,但我最近不得不做类似的事情……看到这是多么困难,我想出了一个更简单的解决scheme:

  1. 创build一个包含EditText和Image的XML布局
  2. 子类FrameLayout并膨胀XML布局
  3. 为点击侦听器添加代码以及您想要的任何其他行为

在我的情况下,我需要一个EditText,可以用button清除文本。 我想它看起来像SearchView,但由于许多原因,我不想使用该类。 下面的例子显示了我是如何完成这个的。 尽pipe不需要改变焦点,但原理是相同的,我认为发布实际工作代码比组合一个可能不完全按照我的意图工作的例子更有利:

这是我的布局:clearable_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> 

这里是膨胀布局的类:ClearableEditText.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. 把drawable资源改成任何你想要的东西……在我的情况下,它是一个灰色的X
  2. 将焦点更改侦听器添加到编辑文本…

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

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

for left drawable click listener

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

Compound drawables are not supposed to be clickable. It is cleaner to use separate views in a horizontal LinearLayout and use a click handler on them.

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

Here's my simple solution, just place ImageButton over 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> 

It is all great but why not to make it really simple?

I have faced with that also not so long ago…and android touchlistiner works great but gives limitation in usage..and I came to another solution and I hope that will help you:

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

在这里输入图像描述 Now you can create ImageClick listener or event and do what ever you want with text. This edittext_round_corners.xml file

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

I would like to suggest a way for drawable left! I tried this code and works.

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

I implemented @aristo_sh answer in Mono.Droid (Xamarin), since it's a delegate anonymous method you can't return true or false you have to take take of e.Event.Handled. I am also hiding the keyboard on click

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

Simply copy paste the following code and it does the trick.

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

Sharing my generalized solution for handling TextView compound drawable click and touch events.

First we need a touch event handler:

 /** * 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 - ie within {@code drawableBounds}. * If using fuzz, may return negative coordinates. */ protected abstract boolean onDrawableTouch(View v, int drawableIndex, Rect drawableBounds, MotionEvent event); } 

Now you can process any touch events on any compound drawable of any TextView you like this way:

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

Only interested in clicks? Just filter out by MotionEvent action:

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

Again we can easily handle clicks on any compound drawable of any 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; } } }); 

Hope you liked it as I did. I will try to keep it updated here and in related gist if anything changes.

I have created a simple custom touch listener class instead of a custom 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; } 

}

There will be no drawable when the EditText is blank. A drawable will show when we started editing for clear the EditText.

You can just set the touch listener

mEditText.setOnTouchListener(new MyTouchListener(mEditText));

For anyone who does not want to implement the monstrous click handling. You can achieve the same with a RelativeLayout . With that you even have free handling of the positioning of the drawable.

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

The ImageView position will be the same as you would use drawableEnd – plus you don't need all the touch listener handling. Just a click listener for the ImageView and you are good to go.

This works fro me:) may this help you as well

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