web-dev-qa-db-fra.com

Gestion des événements de clic sur un dessin dans un EditText

J'ai ajouté une image à droite du texte dans un widget EditText, à l'aide du code XML suivant:

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

Mais je veux effacer la EditText lorsque l’image intégrée est cliquée. Comment puis-je faire ceci?

201
Manikandan

En fait, vous n'avez pas besoin d'étendre une classe. Disons que j'ai un EditText editComment avec 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() car nous souhaitons connaître la position réelle de l'écran tactile, sans rapport avec le parent. 

Pour obtenir un clic gauche

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

Très, très bien, merci à tous ceux qui ont contribué à cette discussion. Donc, si vous ne voulez pas gérer l'inconvénient d'étendre la classe, vous pouvez faire ce qui suit (implémenté pour le bon dessinable)

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

Et voici l'implémentation d'un auditeur à nu selon la réponse 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);

}
77
Bostone

Considérer ce qui suit. Ce n'est pas la solution la plus élégante mais ça marche, je viens de la tester.

  1. Créez une classe EditText personnalisée 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. Changez votre mise en page XML en ceci (où com.example est le nom réel de votre package de projet):

    <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. Enfin, ajoutez ceci (ou quelque chose de similaire) à votre activité:

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

Je suis peut-être un peu mal à l'aise avec le calcul des limites de contact pour le dessin imbriqué, mais vous voyez l'idée.

J'espère que ça aide.

27
RyanM

J'ai créé une classe abstraite utile DrawableClickListener qui implémente OnTouchListener.

En plus de la classe DrawableClickListener, j'ai également créé 4 classes abstraites supplémentaires qui étendent la classe DrawableClickListener et gèrent le clic de la zone dessinée pour le quadrant correct.

  • LeftDrawableClickListener
  • TopDrawableClickListener
  • RightDrawableClickListener
  • BottomDrawableClickListener

Point à considérer

Une chose à considérer est que les images ne sont pas redimensionnées si cela est fait de cette façon; les images doivent donc être correctement dimensionnées avant d'être placées dans le (s) dossier (s) res/drawable.

Si vous définissez un LinearLayout contenant un ImageView et un TextView, il est beaucoup plus facile de manipuler la taille de l'image affichée.


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

    }

}
20
MattWeiler

L'utilisation de contains(x,y) par cette dernière contribution ne fonctionnera pas directement sur le résultat de getBounds() (sauf, par coïncidence, lors de l'utilisation des éléments "à gauche"). La méthode getBounds fournit uniquement les points Rect définissant l'élément dessisable normalisé avec Origine à 0,0; vous devez donc effectuer le calcul du message d'origine pour déterminer si le clic est dans la zone de dessinable dans le contexte. des dimensions de EditText contenant, mais changez-le en haut, à droite, à gauche, etc. Sinon, vous pouvez décrire une variable Rect dont les coordonnées sont en fait relatives à sa position dans le conteneur EditText et utiliser contains(), bien que vous fassiez les mêmes calculs .

En combinant les deux, vous obtenez une solution plutôt complète. J'ai seulement ajouté un attribut d'instance consumesEvent qui permet à l'utilisateur de l'API de décider si l'événement click doit être transmis ou non en utilisant ses résultats pour définir ACTION_CANCEL ou non.

De plus, je ne vois pas pourquoi les valeurs bounds et actionX, actionY sont des attributs d'instance plutôt que simplement locales sur la pile.

Voici une découpe d'une mise en œuvre basée sur ce qui précède que j'ai mis en place. Il corrige un problème qui nécessite de renvoyer false pour que l'événement soit consommé correctement. Il ajoute un facteur "fuzz" à. Dans mon cas d'utilisation d'une icône de commande vocale dans un champ EditText, je trouvais difficile de cliquer, de sorte que le fuzz augmente les limites effectives considérées comme étant en cliquant sur le dessin. Pour moi, 15 a bien fonctionné. Je n'avais besoin que de drawableRight et je n'ai donc pas intégré les calculs aux autres, pour économiser de l'espace, mais vous voyez l'idée.

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

Son très simple . Disons que vous avez un dessin sur le côté gauche de votre EditText 'txtsearch' . Suivre fera l'affaire.

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 vous voulez dessiner à droite, changez l'instruction if en:

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

De même, vous pouvez le faire pour tous les tirables composés.

txtsearch.getTotalPaddingTop()
txtsearch.getTotalPaddingBottom()

Cet appel de méthode retourne tout le rembourrage de ce côté, y compris tous les tirables. Vous pouvez l'utiliser même pour TextView, Button, etc.

Cliquez sur ici pour consulter le site du développeur Android.

11
Vishnuvathsan

Je pense que c'est beaucoup plus facile si nous utilisons quelques astuces :)

  1. Créez un bouton image avec votre icône et définissez son arrière-plan couleur à être transparente .
  2. Placez le bouton image sur l’EditText et coz le côté droit
  3. Implémentez le programme d'écoute onclick du bouton pour exécuter votre fonction

Terminé

10
Bear

Dans le prolongement de l’idée de RyanM, j’ai créé une version plus flexible, qui prend en charge tous les types pouvant être dessinés (haut, bas, gauche, droite). Tandis que le code ci-dessous étend TextView, l’adapter à un EditText n’est qu’un cas de permutation de "extend TextView" avec "extend EditText". L'instanciation du widget à partir de XML est identique à celle de l'exemple de RyanM, à l'exception du nom du 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;
}}

DrawableClickListener est aussi simple que cela:

public interface DrawableClickListener {

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

Et puis la mise en œuvre réelle:

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

p.s .: Si vous ne définissez pas l'écouteur, toucher le TextView provoquera une exception NullPointerException. Vous voudrez peut-être ajouter un peu plus de paranoïa dans le code.

6
ptashek

ça marche pour moi,

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;
        }
    });
6
varotariya vajsi

Il suffit de copier/coller le code suivant et le tour est joué.

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;
        }
    });
3
Prashant Paliwal

Je sais que c'est assez vieux, mais j'ai récemment eu à faire quelque chose de similaire ... Après avoir constaté à quel point c'est difficile, j'ai proposé une solution beaucoup plus simple:

  1. Créer une mise en page XML contenant les propriétés EditText et Image
  2. Sous-classe FrameLayout et gonfler la mise en page XML
  3. Ajoutez du code pour l'écouteur de clics et tout autre comportement souhaité

Dans mon cas, j'avais besoin d'un EditText capable d'effacer le texte avec un bouton. Je voulais que cela ressemble à SearchView, mais pour un certain nombre de raisons, je ne voulais pas utiliser cette classe. L'exemple ci-dessous montre comment j'ai accompli cela. Même s'il ne s'agit pas d'un changement de focus, les principes sont les mêmes et je me suis dit qu'il serait plus avantageux de publier du code qui fonctionne réellement que de créer un exemple qui pourrait ne pas fonctionner exactement comme je le souhaitais:

Voici ma mise en page: 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>

Et voici la classe qui gonfle cette mise en page: 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;
        }
    }
}

Pour que cette réponse corresponde davantage à la question, il convient de suivre les étapes suivantes:

  1. Changez la ressource extractible en ce que vous voulez ... Dans mon cas, c’était un X gris.
  2. Ajouter un auditeur de changement de focus au texte modifié ...
3
Justin

et si tirable est à gauche, cela vous aidera. (pour ceux qui travaillent avec la mise en page 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;
        }
    });
3
Ali Ziaee
<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>
2
PNR

Les tirables composés ne sont pas supposés être cliquables. Il est plus propre d’utiliser des vues séparées dans un LinearLayout horizontal et d’utiliser un gestionnaire de clics dessus. 

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

Pour tous ceux qui ne veulent pas mettre en œuvre la gestion monstrueuse des clics. Vous pouvez réaliser la même chose avec un RelativeLayout. Avec cela, vous avez même la manipulation libre du positionnement du dessinable.

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

La position ImageView sera la même que celle que vous utiliseriez drawableEnd - de plus, vous n'avez pas besoin de toute la gestion de l'écoute tactile. Juste un écouteur de clic pour le ImageView et vous êtes prêt à partir.

1
Murat Karagöz

Cela fonctionne pour moi :) que cela vous aide aussi

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;
        }
    });
1
zohaib khaliq

Il est préférable d’avoir le bouton Image à droite du texte et de donner une marge de présentation négative qui chevauche le texte. Définissez le programme d'écoute sur le bouton d'image et effectuez les opérations.

1
Ramanand Singh

pour écouteur de clic dessiné à gauche

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;
        }
    });
1
Harish Gyanani

Suivez le code ci-dessous pour les tirages à droite, à gauche, en haut et en bas:

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

}

1
Rohan Lodhi

C'est génial, mais pourquoi ne pas simplifier les choses?

J'ai aussi fait face à cela il n'y a pas si longtemps ... et Android Touchlistiner fonctionne très bien, mais limite l'utilisation ... et je suis arrivé à une autre solution et j'espère que cela vous aidera:

    <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 Vous pouvez maintenant créer un écouteur ou un événement ImageClick et faire ce que vous voulez avec du texte. Ce fichier 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>

1
Jevgenij Kononov
@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);

    }
1
Zahid Naqvi

Partage de ma solution généralisée de gestion des événements de clic et de toucher pouvant être dessinés par le composé TextView.

Nous avons d’abord besoin d’un gestionnaire d’événements tactiles:

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

Vous pouvez maintenant traiter tous les événements tactiles sur n'importe quel composé pouvant être dessiné de la manière suivante:

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

Seulement intéressé par les clics? Il suffit de filtrer par action 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);
}

Encore une fois, nous pouvons facilement gérer les clics sur n'importe quel composé pouvant être dessiné de n'importe quel 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;
                }
            }
        });

J'espère que vous avez aimé comme moi. Je vais essayer de le garder à jour ici et dans Gist lié si quelque chose change.

0
Amaksoft

J'ai créé une classe d'écoute tactile personnalisée simple au lieu d'un EditText personnalisé

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;

}

}

Il n'y aura pas de dessin lorsque l'EditText est vide. Un dessinable montrera quand nous avons commencé à éditer pour effacer le EditText.

Vous pouvez simplement définir l'auditeur tactile

mEditText.setOnTouchListener (nouveau MyTouchListener (mEditText));

0
sreenadh

J'ai fait quelque chose comme ça 

            <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>
0
Piotr Badura

Je voudrais suggérer un moyen de dessiner gauche! J'ai essayé ce code et fonctionne.

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;
        }
    });
}
0
Tirthankar Kundu

J'ai vu plusieurs solutions, mais aucune d'entre elles ne m'a convaincu. Très compliqué ou trop simple (non réutilisable).

C'est mon approche préférée en ce moment:

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

Et voici l'auditeur tactile réutilisable:

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

Vous pouvez regarder le Gist ici.

0
Sotti

J'ai implémenté @aristo_sh answer dans Mono.Droid (Xamarin), puisqu'il s'agit d'une méthode anonyme pour les délégués, vous ne pouvez pas renvoyer true ou false, vous devez prendre e.Event.Handled. Je cache aussi le clavier au clic

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;
                        }
                    }
                };
0
Yohan Dahmani

Le kotlin est un excellent langage où chaque classe pourrait être étendue avec de nouvelles méthodes. Introduisons une nouvelle méthode pour la classe EditText qui capturera les clics dessinés à droite.

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

Vous pouvez voir qu'il prend la fonction de rappel en tant qu'argument qui est appelé lorsque l'utilisateur clique sur le droit de dessin.

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

Utiliser un tampon de visualisation de texte pouvant être espionné pourrait être une solution. Regardez ce didacticiel court et pertinent: pour un, il est beaucoup plus facile de créer des événements de clic

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

0
Javene CPP McGowan

Tant de solutions, mais aucune n’a fonctionné pour moi lorsque j’avais deux champs à la suite . C’est une solution de rechange pour l’ajout de boutons clairs permettant d’éditer du texte, qui a fonctionné pour moi dans les cas où j’ai deux champs ou un champ dans un rangée. Écrit en kotlin!

@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
}
0
Renetik

Voici ma solution simple, il suffit de placer ImageButton sur 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>
0
almisoft

J'applique une solution courte qui convient même pour des fragments de dialogue.

 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;
                }
            });
0
Eduard Fomin

Les solutions ci-dessus fonctionnent, mais elles ont un effet secondaire. Si vous avez un EditText avec le droit dessinable comme

 enter image description here

vous obtiendrez un bouton PATE après chaque clic sur le dessinable. Voir Comment désactiver coller dans onClickListener pour le droit de dessin d'un EditText Android (dans l'icône EditText) .

0
CoolMind