EditText içindeki çekilebilir bir karttaki tıklama olaylarını işleme


239

EditTextAşağıdaki XML'i kullanarak bir widget'ta metnin sağına bir resim ekledim :

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

Ancak EditTextkatıştırılmış görüntünün tıklandığı zamanı temizlemek istiyorum . Bunu nasıl yapabilirim?


Yanıtlar:


358

Aslında herhangi bir sınıfı genişletmeniz gerekmez. Diyelim ki drawableRight ile bir EditText editComment var

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

Biz getRawX()biz ebeveyn göre değil, ekrandaki dokunmatik gerçek konumunu almak istiyorum çünkü.

Sol tarafa tıklamak için

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

2
@ user2848783 bunu sol çekilebilirliğime nasıl ayarlayabilirim?
Kadir Hüseyin

10
@AngeloSevent.getRawX()event.getX()
Pratik Butani

4
Bir not: "return false" yerine; "doğru dön"; aksi halde ACTION_DOWN -> ACTION_UP sonrasında tetiklenmez.
tomurka

9
Dolgu eklerseniz, bunun yanı sıra getRight()dolgu varsa çekmecenin hakkı olmayacak şekilde TextView'in sağını alır. İfadenizin - editComment.getPaddingRight()sonuna eklemek ifişe yarayacak.
kassim

21
EditText öğesinin üst öğesi ekranın soluyla hizalanmamışsa bu çalışmaz. Event.getRawX () yerine event.getX () ve editText.getRight () yerine editText.getWidth () kullanmalısınız
Fletcher Johns

85

Bu tartışmaya katkıda bulunan herkese çok ama çok iyi. Bu nedenle, sınıfı genişletmenin sıkıntısıyla uğraşmak istemiyorsanız aşağıdakileri yapabilirsiniz (yalnızca doğru çekilebilir için uygulanır)

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

İşte @ Mark'ın cevabına dayanan çıplak kemik dinleyici uygulaması

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

}

3
Doğru konumu elde etmek için x'e v.getLeft () ve y'ye v.getTop () eklemelisiniz.
André

3
Aslında değiştirmeniz gerekir v.getRight()göre v.getWidth().
Speedy

2
fuzz faktörünüzün DPI ile ölçeklendirilmesi gerektiğini unutmayın, ldpi'de 10 piksel xxhdpi'de 10 pikselden tamamen farklı bir şeydir.
RaB

4
Fuzz ne için? Lütfen açıkla.
Юрій Мазуревич

1
Görünüşe fuzzetkili bir daha kolay küçük çekilebilir dokunun hale tappable alanı biraz daha büyük hale getirir.
ban-geoengineering

28

Aşağıdakileri göz önünde bulundur. En zarif çözüm değil ama işe yarıyor, sadece test ettim.

  1. Özelleştirilmiş bir EditTextsınıf oluşturun 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. Düzen XML'nizi şu şekilde değiştirin ( com.examplegerçek proje paketi adınız nerede ):

    <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. Son olarak, bunu (veya benzer bir şeyi) etkinliğinize ekleyin:

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

İç içe çekilebilir için dokunmatik sınırların hesaplanmasıyla biraz uzakta olabilirim ama fikri anladınız.

Umarım bu yardımcı olur.


Aslında, MotionEvent'in değiştirilmesinin cesaretsiz bir uygulama olduğunu duydum, muhtemelen farklı platformlarda kırılacak tanımsız davranışlara yol açıyor, bu yüzden belki de daha iyi bir çözüm stackoverflow.com/a/6235602
Giulio Piancastelli

@RyanM, TextViewyerine kullandım EditText. Kodu aldım ve TextView(simgesine değil, üzerindeki herhangi bir alana TextView) tıklarsam yöntem onTouchEvent(MotionEvent event)çağrılır. Yani, herhangi bir ek sınıf olmadan OnClickListenernormal bir uygulama yapabilirimTextViewCustomEditText
Maksim Dmitriev

@RyanM, Kullanmak yerine this.getRight()-rBounds.width()neden kullanmıyorsunuz this.getMeasuredWidth() - this.getCompoundPaddingRight()? Çekmecenin dolgusu ile ilgilenmez ve çekmecenin sınırından kurtulmaz mı?
Vino

@RyanM çapraz buton tıklama olayı dokunuşta görüntü nasıl değiştirilir?
Kadir Hussain

Özel sürümleri, EditTextlolipop öncesi cihazlarda appcompat kullanılırken uygun widget'ların renklendirilmesini desteklemez. AppCompatEditTextÖzel EditText'inizin ana sınıfı olarak kullanın
Tomask

24

OnTouchListener uygulayan kullanışlı bir soyut sınıf DrawableClickListener oluşturdum .

Ek olarak DrawableClickListener sınıfında, ben de genişletmek 4 ek soyut sınıflar yarattı DrawableClickListener sınıfını ve doğru kadranda için çekilebilir alanın tıklayarak işlemek.

  • LeftDrawableClickListener
  • TopDrawableClickListener
  • RightDrawableClickListener
  • BottomDrawableClickListener

Dikkate Alınması Gerekenler

Dikkate alınması gereken bir şey, bu şekilde yapılırsa görüntülerin yeniden boyutlandırılmamasıdır; bu nedenle res / çekilebilir klasörlere yerleştirilmeden önce görüntüler doğru şekilde ölçeklendirilmelidir .

Bir ImageView ve bir TextView içeren bir LinearLayout tanımlarsanız , görüntülenen görüntünün boyutunu değiştirmek çok daha kolaydır.


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

    }

}

14

Çok basit. Diyelim ki EditText 'txtsearch'ünüzün sol tarafında bir çekmeceniz var. Aşağıdaki hile yapacak.

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

Doğru çekilebilir için if ifadesini şu şekilde değiştirin:

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

Benzer şekilde, tüm bileşik çekilebilir malzemeler için de yapabilirsiniz.

txtsearch.getTotalPaddingTop()
txtsearch.getTotalPaddingBottom()

Bu yöntem çağrısı, çekilebilirler de dahil olmak üzere o taraftaki tüm dolguları döndürür. Bunu TextView, Button vb.İçin bile kullanabilirsiniz.

Android geliştirici sitesinden referans için buraya tıklayın .


1
Bence bu doğru bir cevaptır, doğru olanın her yere geri döndürülmesi hariç. Yalnızca olayın tüketilmesi gerektiğinde true değerine dönmenizi öneririm (dokunma hareketi doğru alanda oldu).
Bianca Daniciuc

12

Bazı hileler kullanırsak çok daha kolay olduğunu düşünüyorum :)

  1. Simgenizle bir görüntü düğmesi oluşturun ve arka plan rengini şeffaf olarak ayarlayın .
  2. Görüntü düğmesini EditText üzerine koyun ve coz sağ tarafa koyun
  3. İşlevinizi yürütmek için düğmenin onclick dinleyicisini uygulayın

Bitti


1
RelativeLayoutDüzgün konumlandırma elde etmek için kullanılır , diğer çözümlerden daha az kıvrımlı ve bakımı daha az kodlanmış gibi görünür.
C0D3LIC1OU5

12

Bu son katkının kullanımı contains(x,y)doğrudan sonuç üzerinde çalışmayacaktır getBounds()(tesadüf hariç, "sol" çekilebilir malzemeler kullanıldığında). getBoundsYöntem yalnızca sağlar Rect0,0 kökenli olan normalize çekilebilir öğenin tanımlayan noktaları - öyleyse, aslında tıklama bağlamında çekilebilir alanında olup olmadığını öğrenmek için orijinal yazının matematik yapmak gerekir EditText boyutlarını içeren, ancak üst, sağ, sol vb. için değiştirin. Alternatif olarak Rect, aslında EditTextkaptaki konumuna göre koordinatları olan vecontains() sonunda aynı matematik yapıyoruz rağmen.

Her ikisini de birleştirmek size oldukça eksiksiz bir çözüm sunar, yalnızca consumesEventAPI kullanıcısının tıklama etkinliğinin ayarlanıp ayarlanmayacağını kullanarak click olayının iletilip iletilmeyeceğine karar vermesini sağlayan bir örnek özelliği ekledim ACTION_CANCEL.

Ayrıca, boundsve actionX, actionYdeğerlerin neden yığın üzerinde yerel yerine örnek öznitelikleri olduğunu göremiyorum .

İşte bir araya getirdiğim yukarıdakilere dayanan bir uygulamadan bir kesme. Düzgün bir şekilde yanlış döndürmeniz gereken olayı tüketen bir sorunu giderir. "Fuzz" faktörünü ekler. Bir EditTextalanda Ses kontrolü simgesi kullanmam durumunda, tıklamayı zor buldum, bu yüzden tüylenme çekilebilir tıklamayı kabul eden etkili sınırları artırır. Benim için 15iyi çalıştı. Sadece ihtiyacım vardı, drawableRightbu yüzden yer kazanmak için matematiği diğerlerine takmadım, ama fikri görüyorsun.

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

8

Fikri RyanM tarafından genişleterek tüm çekilebilir türleri (üst, alt, sol, sağ) destekleyen daha esnek bir versiyon oluşturdum. Aşağıdaki kod TextView'ı genişletirken, bir EditText için uyarlamak "TextView'u genişlet" i "EditText'i genişlet" ile değiştirmektir. Widget'ın XML örneğinin oluşturulması, RyanM örneğinde, widget adı çubuğu ile aynıdır.


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 şu kadar basittir:

public interface DrawableClickListener {

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

Ve sonra gerçek uygulama:

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

        case RIGHT:
            doSomethingB();
            break;

        case BOTTOM:
            doSomethingC();
            break;

        case TOP:
            doSomethingD();
            break;

        default:
            break;
    }
}}

ps: Dinleyiciyi ayarlamazsanız, TextView öğesine dokunmak NullPointerException özelliğine neden olur. Koda biraz daha paranoya eklemek isteyebilirsiniz.


Kodunuz çalışmıyor gibi görünüyor, sadece test ettim ve çekilebilir dokunduğumda hiçbir şey olmuyor.
Thiago

8

Kotlin, her sınıfın yeni yöntemlerle genişletilebileceği harika bir dildir. Sağ çekilebilir tıklamaları yakalayacak EditText sınıfı için yeni bir yöntem sunalım.

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

Geri çağrı işlevini, kullanıcı sağ çekilebilir öğeye tıkladığında çağrılan bağımsız değişken olarak görür.

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

7

benim için çalışıyor,

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

İsabet dikdörtgenin başlangıcını belirlerken metni düzenlemek için varsa, sağ dolguyu çıkarmanız gerekir.
farid_z

4

Bunun oldukça eski olduğunu biliyorum, ama son zamanlarda benzer bir şey yapmak zorunda kaldım ... Bunun ne kadar zor olduğunu gördükten sonra, çok daha basit bir çözüm buldum:

  1. EditText ve Image içeren bir XML düzeni oluşturma
  2. Alt sınıf FrameLayout ve XML düzenini şişirmek
  3. Tıklama dinleyicisi ve istediğiniz diğer davranışlar için kod ekleyin

Benim durumumda, bir düğme ile metni temizleme yeteneğine sahip bir EditText gerekiyordu. SearchView gibi görünmesini istedim, ancak birkaç nedenden dolayı bu sınıfı kullanmak istemedim. Aşağıdaki örnek bunu nasıl başardığımı göstermektedir. Odak değişikliği ile ilgili olmasa da, ilkeler aynıdır ve gerçek çalışma kodunu yayınlamanın tam olarak istediğim gibi çalışmayabilecek bir örnek oluşturmaktan daha yararlı olacağını düşündüm:

İşte düzenim: 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>

Ve işte bu düzeni şişiren Sınıf: 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;
        }
    }
}

Bu cevabı soru ile daha uyumlu hale getirmek için aşağıdaki adımlar atılmalıdır:

  1. Çekilebilir kaynağı istediğiniz gibi değiştirin ... Benim durumumda gri bir X idi
  2. Düzenleme metnine odak değişiklik dinleyicisi ekleme ...

3

ve çekilebilir solda ise, bu size yardımcı olacaktır. (RTL düzeni ile çalışanlar için)

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

Bu "getRawX" mutlak konumlarını "getRight" göreli konumlarıyla karıştırmaktadır. EditText üzerinde sağ veya sol kenar boşluğu ayarlarsanız, tıklama yanlış koordinatlarda tetiklendiğinde bunun nasıl kırıldığını görürsünüz.
Sotti

3

Aşağıdaki kodu kopyalayıp yapıştırmanız yeterlidir.

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

1
Bu benim için çalıştı ama getRawX () yerine getX () kullanmak zorunda kaldı. Bence getRawX () sadece görünüm ekranın sol kenarında ise çalışır.
Glenn

1
Pozisyonların hesaplanması yanlış. Mutlak koordinatları "getRawX ()", "getRight ()" gibi göreli koordinatlarla karıştırıyor
Sotti

3

Xamarin Android'de önceki çözümlerin hiçbiri benim için çalışmadı . Aşağıdakileri kullanarak doğru çekilebilir tıklama dinleyicisini çalıştırabildim:

Aşağıdaki OnEditTextToucholay dinleyicisini oluşturun:

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

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

            return;
        }

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

            e.Handled = true;
        }

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

Touch etkinliğine abone olun:

_autoCompleteTextViewSearch.Touch += OnEditTextTouch;

2

Her şey harika ama neden gerçekten basit yapmıyorsunuz?

Bununla çok uzun zaman önce de karşılaşmadım ... ve android touchlistiner harika çalışıyor ancak kullanımda sınırlama veriyor ... ve başka bir çözüme geldim ve umarım size yardımcı olur:

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

resim açıklamasını buraya girin Artık ImageClick dinleyicisi veya etkinliği oluşturabilir ve metinle istediğinizi yapabilirsiniz. Bu edittext_round_corners.xml dosyası

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


Bu yaklaşımla ilgili sorun, EditText üzerinde metin boyutunu değiştirmeye başlar başlamaz ayrı düşüyor olmasıdır. Bunun sadece geliştirici tarafında olduğunu düşünebilirsiniz, ancak cihazların ayarlarda metin boyutu olduğu kadar değil. EditText'te sp yerine dp'yi kullanmaktan kaçınabilirsiniz, ancak işleri daha da kötüleştirir. Diğer sorunlar çok satırlı EditTexts işleme gibi şeylerdir.
Sotti

Bunu çok satırlı arama için hiç kullanmadım, çok üzgünüm bu sorunun ortaya çıkabileceğini hiç düşünmemiştim. Muhtemelen çoklu hat için engelleme yardımcı olacaktır. Ne olduğunu görmek için uygulamanın veya görünümün ekran görüntüsünü ekleyebilir misiniz? Ve bunu çözmeye çalışacağım ve belki de (bu kodu düzelt) ve gelecekteki kullanım için bana yardım edeceğim. Teşekkürler.
Jevgenij Kononov

Çoğaltmak çok kolaydır, 2 satır eklediğinizde düzen önizlemesinde bile olur.
Sotti

İçin bir arka plan EditTextolmalıdır android:background="@android:color/transparent".
CoolMind

1

ImageButton'ın metin düzenleme hakkı olması ve metin düzenleme ile çakışması için negatif mizanpaj marjı vermesi daha iyidir. ImageButton üzerinde dinleyiciyi ayarlayın ve işlemleri gerçekleştirin.


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

Bu yaklaşımla ilgili sorun, EditText üzerinde metin boyutunu değiştirmeye başlar başlamaz ayrı düşüyor olmasıdır. Bunun sadece geliştirici tarafında olduğunu düşünebilirsiniz, ancak cihazların ayarlarda metin boyutu olduğu kadar değil. EditText'te sp yerine dp'yi kullanmaktan kaçınabilirsiniz, ancak işleri daha da kötüleştirir. Diğer problemler, çok satırlı EditTexts
Sotti

1

sol çekilebilir tıklama dinleyicisi için

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

Bu "getRawX" mutlak konumlarını "getRight" göreli konumlarıyla karıştırmaktadır. EditText üzerinde sağ veya sol kenar boşluğu ayarlarsanız, tıklama yanlış koordinatlarda tetiklendiğinde bunun nasıl kırıldığını görürsünüz.
Sotti

1

Bileşik çekilebilir kliklerin tıklanabilir olması gerekmez. Yatay bir LinearLayout'ta ayrı görünümler kullanmak ve üzerlerinde bir tıklama işleyicisi kullanmak daha temizdir.

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

Bu yaklaşımla ilgili sorun, EditText üzerinde metin boyutunu değiştirmeye başlar başlamaz ayrı düşüyor olmasıdır. Bunun sadece geliştirici tarafında olduğunu düşünebilirsiniz, ancak cihazların ayarlarda metin boyutu olduğu kadar değil. EditText'te sp yerine dp'yi kullanmaktan kaçınabilirsiniz, ancak işleri daha da kötüleştirir. Diğer sorunlar çok satırlı EditTexts işleme gibi şeylerdir.
Sotti

1

Canavar tıklama işleme uygulamak istemeyen herkes için. Aynı şeyi a RelativeLayout. Bununla beraber, çekmecenin konumunu serbestçe kullanabilirsiniz.

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

ImageViewEğer kullandığınız gibi pozisyon aynı olacaktır drawableEnd- artı tüm dokunmatik dinleyici işleme gerek yoktur. Sadece bir tıklama dinleyici ImageViewve gitmek için iyidir.


Bu yaklaşımla ilgili sorun, EditText üzerinde metin boyutunu değiştirmeye başlar başlamaz ayrı düşüyor olmasıdır. Bunun sadece geliştirici tarafında olduğunu düşünebilirsiniz, ancak cihazların ayarlarda metin boyutu olduğu kadar değil. EditText'te sp yerine dp'yi kullanmaktan kaçınabilirsiniz, ancak işleri daha da kötüleştirir. Diğer problemler, çok satırlı EditTexts
Sotti

1

Bu benim için çalışıyor :) bu da sana yardımcı olabilir

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

Bu "getRawX" mutlak konumlarını "getRight" göreli konumlarıyla karıştırmaktadır. EditText üzerinde sağ veya sol kenar boşluğu ayarlarsanız, tıklama yanlış koordinatlarda tetiklendiğinde bunun nasıl kırıldığını görürsünüz.
Sotti

düzenleme metninde sağ kenar boşluğu ekledim, kodum hala mükemmel çalışıyor
zohaib khaliq

1

Birkaç çözüm gördüm ama hiçbiri tarafından ikna olmadım. Çok karmaşık veya çok basit (tekrar kullanılamaz).

Şu anda benim en sevdiğim yaklaşım:

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

Ve bu yeniden kullanılabilir dokunmatik dinleyici:

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

public abstract class OnEditTextRightDrawableTouchListener implements OnTouchListener {

  private final EditText mEditText;

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

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

  public abstract void OnDrawableClick();
}

Gist'e buradan bakabilirsiniz.


1

Çekilebilir sağ, sol, yukarı, aşağı tıklama için aşağıdaki kodu izleyin:

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

Kotlin'de uyguladım

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

0

İşte benim basit çözümüm, sadece ImageButtonüzerine yerleştirin 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

Çekilebilir sol için bir yol önermek istiyorum! Bu kodu denedim ve çalışıyor.

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

Bu "getRawX" mutlak konumlarını "getRight" göreli konumlarıyla karıştırmaktadır. EditText üzerinde sağ veya sol kenar boşluğu ayarlarsanız, tıklama yanlış koordinatlarda tetiklendiğinde bunun nasıl kırıldığını görürsünüz.
Sotti

0

Mono.Droid'de (Xamarin) @aristo_sh cevabını uyguladım, çünkü delege anonim bir yöntem olduğundan e.Event.Handled'i almak zorunda olduğunuz doğru veya yanlış döndüremezsiniz. Ben de klavyeyi tıkladığında saklıyorum

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

TextView bileşik çekilebilir tıklama ve dokunma olaylarını işlemek için genel çözümümü paylaşıyorum.

Öncelikle bir dokunma olayı işleyicisine ihtiyacımız var:

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

Artık herhangi bir TextView öğesinden çekilebilir herhangi bir bileşikteki herhangi bir dokunma olayını şu şekilde işleyebilirsiniz:

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

Yalnızca tıklamalarla mı ilgileniyorsunuz? MotionEvent eylemine göre filtreleyin:

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

Yine, herhangi bir TextView'den çekilebilir herhangi bir bileşiğin tıklamalarını kolayca halledebiliriz:

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

Umarım benim gibi sevmişsinizdir. Bir şey değişirse , burada ve ilgili özette güncel tutmaya çalışacağım .


0

Özel bir EditText yerine basit bir özel dokunmatik dinleyici sınıfı oluşturdum

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

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

    setupDrawable(this.editText);
}

private void setupDrawable(final EditText editText) {
    editText.addTextChangedListener(new TextWatcher() {
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {

        }

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
            if(s.length()>0)
                editText.setCompoundDrawablesWithIntrinsicBounds(0,0, R.drawable.clearicon,0);
            else
                editText.setCompoundDrawablesWithIntrinsicBounds(0,0, 0,0);

        }

        @Override
        public void afterTextChanged(Editable s) {

        }
    });
}

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

}

}

EditText boş olduğunda çekilemez. EditText'i temizlemek için düzenlemeye başladığımızda çekilebilir bir sayfa gösterilir.

Sadece dokunmatik dinleyiciyi ayarlayabilirsiniz

mEditText.setOnTouchListener (yeni MyTouchListener (mEditText));


S TouchListener'ın çekilebilir görünürlüğü ve net eylemin kendisini ele alması biraz kafa karıştırıcı. Bu bir dokunma dinleyicisi sorumluluğu değildir ve sınıfın adı yanıltıcıdır. Göreceli konumlar hesaplarken denklemden marjları kaldırmak gerekli değildir. getRight - width bunu yapacak.
Sotti
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.