Manejo de eventos de clic en un drawable dentro de un EditText

He añadido una imagen a la derecha del texto en un widget EditText , utilizando el siguiente 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" /> 

Pero quiero borrar el EditText cuando se hace clic en la imagen incrustada. ¿Cómo puedo hacer esto?

En realidad, no es necesario extender ninguna clase. Digamos que tengo un EditText editComment con un 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() porque queremos obtener la posición real del toque en la pantalla, no en relación con el padre.

Para obtener el clic izquierdo

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

Muy, muy bien, gracias a todos los que contribuyeron a esta discusión. Así que si usted no quiere lidiar con inconvenientes de extender la clase puede hacer lo siguiente (implementado para el derecho sólo estirable)

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

Y aquí está la implementación de oyentes sin hueso basados ​​en la respuesta de @ 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); } 

Considera lo siguiente. No es la solución más elegante, pero funciona, lo probé.

  1. Cree una clase CustomEditText.java personalizada CustomEditText.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. Cambie el XML de su diseño a esto (donde com.example es el nombre real del paquete de proyecto):

     <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. Finalmente, agregue esto (o algo similar) a su actividad:

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

Puedo ser un poco apagado con el cálculo de los límites del tacto para el nested dibujable pero usted consigue la idea.

Espero que esto ayude.

El uso de la última contribución de contains(x,y) no funcionará directamente en el resultado de getBounds() (excepto, por casualidad, cuando se utiliza "left" drawables). El método getBounds sólo proporciona el Rect define los puntos del elemento Rect normalizado con origen en 0,0 – así que, en realidad necesita hacer la matemática del post original para averiguar si el clic está en el área del dibujable en el contexto De las dimensiones que contiene EditText, pero lo cambian por arriba, derecha, izquierda, etc. Alternativamente, podrías describir un Rect que tiene coordenadas realmente relativas a su posición en el contenedor EditText y use contains() , aunque al final estás haciendo el Misma matemática

La combinación de ambos te da una solución bastante completa, sólo agregué un atributo de instancia consumesEvent que permite al usuario de la API decidir si el evento click debe ser pasado o no usando su resultado para establecer ACTION_CANCEL o no.

Además, no veo por qué los bounds y los valores de actionX , actionY son atributos de instancia en lugar de sólo locales en la pila.

He aquí un recorte de una implementación basada en lo anterior que he reunido. Se corrige un problema que para consumir correctamente el evento que necesita para devolver falso. Agrega un factor "fuzz" a. En mi caso de uso de un icono de control de voz en un campo EditText , me resultó difícil hacer clic, por lo que el fuzz aumenta los límites efectivos que se consideran hacer clic en el dibujable. Para mí 15 funcionó bien. Sólo necesitaba drawableRight así que no conecté la matemática en los otros, para ahorrar un poco de espacio, pero usted ve la idea.

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

He creado una clase abstracta útil DrawableClickListener que implementa OnTouchListener .

Además de la clase DrawableClickListener , también creé 4 clases abstractas adicionales que amplían la clase DrawableClickListener y manejan el clic del área dibujable para el cuadrante correcto.

  • LeftDrawableClickListener
  • TopDrawableClickListener
  • RightDrawableClickListener
  • BottomDrawableClickListener

Punto a considerar

Una cosa a considerar es que las imágenes no se redimensionan si se hace de esta manera; Por lo tanto las imágenes deben ser escaladas correctamente antes de ser puesto en el res / drawable carpeta (s).

Si define un LinearLayout que contiene un ImageView y un TextView , es mucho más fácil manipular el tamaño de la imagen que se muestra.


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

Es muy sencillo. Digamos que usted tiene un dibujable en el lado izquierdo de su EditText 'txtsearch'. A continuación le hará el truco.

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

Si desea que la opción if cambie a la derecha:

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

Del mismo modo, usted puede hacerlo para todos los drawables compuestos.

 txtsearch.getTotalPaddingTop() txtsearch.getTotalPaddingBottom() 

Esta llamada de método devuelve todo el relleno en ese lado incluyendo cualquier drawable. Puede usar esto incluso para TextView, Botón, etc.

Haga clic aquí para consultar el sitio de desarrolladores de android.

Creo que es mucho más fácil si usamos algunos trucos 🙂

  1. Cree un botón de imagen con su icono y defina su color de fondo para que sea transparente .
  2. Ponga el botón de imagen en el EditText y de coz el lado derecho
  3. Implementar el listener onclick del botón para ejecutar su función

Hecho

Ampliando la idea por RyanM He creado una versión más flexible, que soporta todos los tipos de dibujo (arriba, abajo, izquierda, derecha). Mientras que el código siguiente extiende TextView, adaptarlo para un EditText es sólo un caso de intercambio "extends TextView" con "extends EditText". Instanciación el widget de XML es idéntico como en el ejemplo de RyanM, bar el nombre del widget.


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

El DrawableClickListener es tan simple como esto:

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

Y luego la implementación real:

 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: Si no establece el listener, tocar el TextView provocará una NullPointerException. Es posible que desee añadir un poco más de paranoia en el código.

Su trabajo para mí,

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

Y si es dibujable está a la izquierda, esto le ayudará. (Para aquellos que trabajan con RTL layout)

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

Sé que esto es bastante viejo, pero recientemente tuve que hacer algo similar … Después de ver lo difícil que es esto, me ocurrió una solución mucho más simple:

  1. Cree un diseño XML que contenga los elementos EditText e Image
  2. Subclase FrameLayout e inflar el diseño XML
  3. Agregue código para el oyente de clics y cualquier otro comportamiento que desee

En mi caso, necesitaba un EditText que tenía la capacidad de borrar el texto con un botón. Quería que parezca SearchView, pero por varias razones no quería usar esa clase. El siguiente ejemplo muestra cómo logré esto. A pesar de que no tiene que ver con el cambio de enfoque, los principios son los mismos y pensé que sería más beneficioso para publicar el código de trabajo real que para armar un ejemplo que puede no funcionar exactamente como me propuse:

Aquí está mi diseño: 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> 

Y aquí está la clase que infla ese diseño: 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; } } } 

To make this answer more in line with the question the following steps should be taken:

  1. Change the drawable resource to whatever you want… In my case it was a gray X
  2. Add a focus change listener to the edit text…

Better to have ImageButton on Right of edit text and give negative layout margin to overlap with edit text. Set listener on ImageButton and perform operations.

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

Introduzca aquí la descripción de la imagen 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; } }); 
  • ¿Hay alguna alternativa para ActionBar en 2.2?
  • Depuración del código de widgets de Android en Eclipse
  • Mapa de Android sin Internet (sin conexión)
  • ¿Cómo mostrar el diálogo en el método onCreate?
  • Compra en la aplicación para widget Android Billing Version 3
  • Cómo cambiar el color del divisor predeterminado para todos los ListViews
  • Cómo agregar iconos a las entradas de PreferenceScreen
  • Cómo mostrar 2 vistas de texto en la misma línea en Android
  • Android: Ocultar divisores secundarios en ExpandableListView
  • ¿Cómo configurar este Layout que se ajuste a cualquier altura de pantalla?
  • Personalizar la apariencia de un <Key>
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.