wake-up-neo.com

Behandlung von Klickereignissen auf einem Drawable innerhalb eines EditText

Ich habe ein Bild rechts vom Text in einem EditText-Widget hinzugefügt und dabei das folgende XML verwendet:

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

Ich möchte jedoch die EditText löschen, wenn das eingebettete Bild angeklickt wird. Wie kann ich das machen?

201
Manikandan

Eigentlich müssen Sie keine Klasse erweitern. Nehmen wir an, ich habe ein EditText editComment mit 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;
    }
});

we getRawX(), weil wir die tatsächliche Position der Berührung auf dem Bildschirm und nicht relativ zum übergeordneten Element ermitteln möchten. 

Klicken Sie auf die linke Seite, um zu klicken

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

Sehr, sehr gut, danke an alle, die zu dieser Diskussion beigetragen haben. Wenn Sie sich also nicht mit Unbequemlichkeiten auseinandersetzen möchten, können Sie Folgendes tun (nur für das richtige Zeichenobjekt)

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

Und hier ist die Implementierung von Bare-Bone-Listenern basierend auf @ Marks Antwort

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

Folgendes berücksichtigen. Es ist nicht die eleganteste Lösung, aber es funktioniert, ich habe es gerade getestet.

  1. Erstellen Sie eine benutzerdefinierte EditText-Klasse 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. Ändern Sie Ihre Layout-XML folgendermaßen (wobei com.example Ihr tatsächlicher Projektpaketname ist):

    <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. Fügen Sie schließlich (oder etwas Ähnliches) zu Ihrer Aktivität hinzu:

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

Ich bin mit der Berechnung der Berührungsgrenzen für das verschachtelte Drawable vielleicht ein bisschen unzufrieden.

Ich hoffe das hilft.

27
RyanM

Ich habe eine nützliche abstrakte Klasse DrawableClickListener erstellt, die OnTouchListener implementiert.

Neben der DrawableClickListener - Klasse habe ich auch 4 zusätzliche abstrakte Klassen erstellt, die die DrawableClickListener - Klasse erweitern und das Anklicken des Zeichenbereichs für den richtigen Quadranten übernehmen.

  • LeftDrawableClickListener
  • TopDrawableClickListener
  • RightDrawableClickListener
  • BottomDrawableClickListener

Zu prüfen

Zu beachten ist, dass die Bilder nicht verkleinert werden, wenn Sie auf diese Weise arbeiten. Daher müssen die Bilder korrekt skaliert werden, bevor sie in den Ordner res/drawable abgelegt werden.

Wenn Sie ein LinearLayout definieren, das ein ImageView und ein TextView enthält, ist es viel einfacher, die Größe des angezeigten Bildes zu ändern.


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

Die Verwendung von contains(x,y) in diesem letzten Beitrag wirkt sich nicht direkt auf das Ergebnis von getBounds() aus (außer zufällig, wenn "linke" Zeichenelemente verwendet werden). Die getBounds-Methode enthält nur die Rect-Definitionspunkte für das mit Origin normalisierte Zeichenelement bei 0,0. Sie müssen also die Berechnungen des ursprünglichen Beitrags durchführen, um herauszufinden, ob sich der Klick im Bereich des Zeichenobjekts im Kontext befindet Alternativ können Sie eine Rect beschreiben, deren Koordinaten tatsächlich relativ zu ihrer Position im EditText-Container liegen. Verwenden Sie contains(), obwohl Sie am Ende die gleiche Mathematik verwenden .

Wenn Sie beide kombinieren, erhalten Sie eine ziemlich vollständige Lösung. Ich habe nur ein Instanzattribut consumesEvent hinzugefügt, mit dem der API-Benutzer entscheiden kann, ob das Klickereignis weitergeleitet werden soll, indem er das Ergebnis zum Setzen von ACTION_CANCEL verwendet.

Ich kann auch nicht erkennen, warum die Werte bounds und actionX, actionY Instanzattribute sind und nicht nur lokal im Stapel.

Hier ist ein Ausschnitt aus einer Implementierung, die auf den oben genannten basiert, die ich zusammengestellt habe. Es behebt ein Problem, durch das das Ereignis, das Sie zurückgeben müssen, um falsch zurückgegeben werden kann, ordnungsgemäß verwendet wird. Es fügt einen "Fuzz" -Faktor hinzu. In meinem Anwendungsfall eines Sprachsteuerungssymbols in einem EditText-Feld fiel es mir schwer, darauf zu klicken, sodass der Effekt die effektiven Grenzen erhöht, die beim Klicken auf das Zeichenobjekt gelten. Für mich hat 15 gut funktioniert. Ich brauchte nur drawableRight, damit ich die Mathematik nicht in die anderen steckte, um Platz zu sparen, aber Sie sehen die Idee.

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

Es ist sehr einfach . Nehmen wir an, Sie haben auf der linken Seite Ihres EditText 'txtsearch' .

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

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

Wenn Sie für rechts gezeichnet werden möchten, ändern Sie die if-Anweisung in:

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

Auf ähnliche Weise können Sie dies für alle zusammengesetzten Drawables tun.

txtsearch.getTotalPaddingTop()
txtsearch.getTotalPaddingBottom()

Dieser Methodenaufruf gibt alle Auffüllungen auf dieser Seite zurück, einschließlich aller Drawables. Sie können dies auch für TextView, Button usw. verwenden.

Klicken Sie auf here als Referenz von der Android-Entwicklerseite.

11
Vishnuvathsan

Ich denke, es ist viel einfacher, wenn wir ein paar Tricks verwenden :)

  1. Erstellen Sie eine Image-Schaltfläche mit Ihrem Symbol und legen Sie den Hintergrund fest Farbe soll transparent sein .
  2. Setzen Sie den Bild-Button auf den EditText und auf die rechte Seite
  3. Implementieren Sie den Onclick-Listener der Schaltfläche, um Ihre -Funktion auszuführen

Erledigt

10
Bear

In Anlehnung an die Idee von RyanM habe ich eine flexiblere Version geschaffen, die alle Zeichenarten (oben, unten, links, rechts) unterstützt. Während der folgende Code TextView erweitert, ist die Anpassung an einen EditText nur ein Fall des Austauschs von "TextView erweitern" mit "EditText erweitern". Die Instantiierung des Widgets aus XML ist identisch wie in RyanMs Beispiel.


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

Der DrawableClickListener ist so einfach wie folgt:

public interface DrawableClickListener {

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

Und dann die eigentliche Implementierung:

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 .: Wenn Sie den Listener nicht festlegen, wird beim Berühren der TextView eine NullPointerException ausgelöst. Möglicherweise möchten Sie dem Code weitere Paranoia hinzufügen.

6
ptashek

es arbeitet für mich,

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

Kopieren Sie einfach den folgenden Code und der Trick funktioniert.

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

Ich weiß, das ist ziemlich alt, aber vor kurzem musste ich etwas Ähnliches machen ... Nachdem ich gesehen hatte, wie schwierig dies ist, habe ich eine viel einfachere Lösung gefunden:

  1. Erstellen Sie ein XML-Layout, das den EditText und das Image enthält
  2. Unterklasse FrameLayout und blase das XML-Layout auf
  3. Fügen Sie Code für den Klicklistener und jedes andere gewünschte Verhalten hinzu

In meinem Fall brauchte ich einen EditText, der den Text mit einer Schaltfläche löschen konnte. Ich wollte, dass es wie SearchView aussieht, aber aus verschiedenen Gründen wollte ich diese Klasse nicht verwenden. Das folgende Beispiel zeigt, wie ich das geschafft habe. Auch wenn es nicht um einen Fokuswechsel geht, sind die Prinzipien die gleichen und ich dachte, es wäre vorteilhafter, tatsächlichen Arbeitscode zu posten, als ein Beispiel zusammenzustellen, das nicht genau so funktioniert, wie ich es mir vorgestellt habe:

Hier ist mein Layout: 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>

Und hier ist die Klasse, die dieses Layout aufbläst: 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;
        }
    }
}

Um diese Antwort besser auf die Frage abzustimmen, sollten die folgenden Schritte ausgeführt werden:

  1. Ändern Sie die zu zeichnende Ressource in das, was Sie möchten ... In meinem Fall war es ein graues X
  2. Hinzufügen eines Fokusänderungslisteners zum Bearbeitungstext ...
3
Justin

und wenn links gezeichnet werden kann, wird dies Ihnen helfen. (für diejenigen, die mit RTL-Layout arbeiten)

 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

Zusammengesetzte Drawables dürfen nicht anklickbar sein. Es ist sauberer, separate Ansichten in einem horizontalen LinearLayout zu verwenden und einen Click-Handler für sie zu verwenden. 

<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

Für alle, die die monströse Klickbehandlung nicht implementieren möchten. Dasselbe können Sie mit einer RelativeLayout erreichen. Damit haben Sie sogar die freie Handhabung der Positionierung des Drawable.

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

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

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

Die ImageView-Position ist die gleiche wie bei drawableEnd. Außerdem benötigen Sie nicht die gesamte Handhabung des Touch-Listeners. Nur ein Klick-Listener für die ImageView und schon kann es losgehen.

1
Murat Karagöz

Das funktioniert für mich :) Vielleicht hilft dir das auch

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

Besser ist es, die Bildschaltfläche rechts neben dem Bearbeitungstext zu haben und einen negativen Layoutrand mit dem Bearbeitungstext zu überlappen. Stellen Sie den Listener auf die Image-Schaltfläche und führen Sie Vorgänge aus.

1
Ramanand Singh

für Linkskizze klicken

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

Befolgen Sie den unten stehenden Code, um rechts, links, oben und unten zu zeichnen:

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

Es ist alles toll, aber warum sollte man es nicht so einfach machen?

Ich habe damit auch vor nicht allzu langer Zeit konfrontiert ... und Android Touchlistiner funktioniert großartig, gibt aber Einschränkungen bei der Verwendung .. und ich kam zu einer anderen Lösung, und ich hoffe, das wird Ihnen helfen:

    <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 Jetzt können Sie einen ImageClick-Listener oder ein Ereignis erstellen und mit Text tun, was Sie möchten. Diese edittext_round_corners.xml-Datei

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

Gemeinsame Nutzung meiner verallgemeinerten Lösung für das Handling von TextView-Ereignissen zum Zeichnen und Ziehen.

Zuerst brauchen wir einen Touch-Event-Handler:

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

    private final String LOG_TAG = "CmpDrawableTouch";

    private final int fuzz;

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

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

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

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

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

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

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

        return false;
    }

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

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

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

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

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

        return bounds;
    }

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

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

Jetzt können Sie alle Berührungsereignisse auf beliebigen zusammengesetzten TextView-Elementen verarbeiten, die Ihnen auf folgende Weise gefallen:

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

Nur an Klicks interessiert? Einfach durch die MotionEvent-Aktion herausfiltern:

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

Auch hier können wir problemlos Klicks auf alle zusammengesetzten TextView-Elemente handhaben:

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

Hoffe es hat dir so gut gefallen wie ich. Ich werde versuchen, es hier und in Gist wenn sich etwas ändert, auf dem neuesten Stand zu halten.

0
Amaksoft

Ich habe anstelle eines benutzerdefinierten EditText eine einfache benutzerdefinierte Touch-Listener-Klasse erstellt

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;

}

}

Wenn der EditText leer ist, ist kein Zeichen möglich. Ein Drawable wird angezeigt, wenn wir mit dem Bearbeiten begonnen haben, um den EditText zu löschen.

Sie können einfach den Touch-Listener einstellen

mEditText.setOnTouchListener (neuer MyTouchListener (mEditText));

0
sreenadh

Ich habe so etwas gemacht 

            <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

Ich würde gerne einen Weg für das Zeichnen von Links vorschlagen!.

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

Ich habe mehrere Lösungen gesehen, aber ich war nicht überzeugt. Entweder sehr kompliziert oder zu einfach (nicht wiederverwendbar).

Das ist im Moment mein Lieblingsansatz:

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

Und das ist der wiederverwendbare Touch-Listener:

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

Sie können den Gist hier sehen.

0
Sotti

Ich habe @aristo_sh answer in Mono.Droid (Xamarin) implementiert, da es sich um eine anonyme Delegatenmethode handelt, die Sie nicht wahr oder falsch zurückgeben können, wenn Sie e.Event.Handled verwenden. Ich verstecke auch die Tastatur beim Klicken

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

Kotlin ist eine großartige Sprache, in der jede Klasse mit neuen Methoden erweitert werden kann. Lasst uns eine neue Methode für die EditText-Klasse einführen, mit der Klicks nach rechts abgefangen werden können.

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

Sie können sehen, dass die Rückruffunktion als Argument verwendet wird, das aufgerufen wird, wenn der Benutzer nach rechts klickt.

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

Die Verwendung eines spannbaren Textview-Puffers könnte eine Lösung sein. Schauen Sie sich dieses kurze Tutorial an: Zum einen ist es viel einfacher, Klickereignisse auszuführen

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

0

So viele Lösungen, aber keine funktionierte für mich, wenn ich zwei Felder in einer Reihe hatte ... Dies ist eine Drop-in-Lösung für das Hinzufügen klarer Schaltflächen zum Editieren von Text. Für mich funktionierte in meinen Situationen, in denen ich zwei Felder oder ein Feld in einer Reihe. In Kotlin geschrieben!

@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("")
            [email protected] true
        }
        false
    }
    return this
}
0
Renetik

Hier ist meine einfache Lösung, platziere einfach ImageButton über 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

Ich wende eine kurze Lösung an, die auch für Dialogfragmente geeignet ist.

 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

Lösungen oben funktionieren, aber sie haben Nebeneffekte. Wenn du einen EditText mit rechts gezeichneten magst

 enter image description here

sie erhalten einen PASTE-Button nach jedem Klick auf das Drawable. Siehe Deaktivieren des Einfügens in onClickListener für das Drawable-Recht eines EditText-Android (innerhalb des Symbols EditText) .

0
CoolMind