2012-10-30 7 views
51

W mojej aplikacji mam EditText z ikoną wyszukiwania po prawej stronie. Użyłem kodu podanego poniżej.Ustawienie onClickListner dla prawych do edycji EditText

<EditText 
     android:id="@+id/search" 
     android:layout_width="0dp" 
     android:layout_height="match_parent" 
     android:layout_margin="4dip" 
     android:layout_weight="1" 
     android:background="@drawable/textfield_search1" 
     android:drawableLeft="@drawable/logo" 
     android:drawableRight="@drawable/search_icon" 
     android:hint="Search Anything..." 
     android:padding="4dip" 
     android:singleLine="true" /> 

Chcę ustawić onClickListner dla obrazu wyszukiwania ikon przypisanych do prawej rozciągliwej z EditText. Jak to jest możliwe ?

+1

dupplicate http://stackoverflow.com/questions/3554377/handling-click-events-on -s-drawable-in-an-edittext – Tobrun

+0

Najprostsze rozwiązanie przy użyciu dostarczonego przez Androida API http://stackoverflow.com/a/26269435/185022 :-) –

+0

To jest najlepsza odpowiedź http://stackoverflow.com/a/37032927/346309 – JPM

Odpowiedz

74
public class CustomEditText extends EditText { 

    private Drawable drawableRight; 
    private Drawable drawableLeft; 
    private Drawable drawableTop; 
    private Drawable drawableBottom; 

    int actionX, actionY; 

    private DrawableClickListener clickListener; 

    public CustomEditText (Context context, AttributeSet attrs) { 
     super(context, attrs); 
     // this Contructure required when you are using this view in xml 
    } 

    public CustomEditText(Context context, AttributeSet attrs, int defStyle) { 
     super(context, attrs, defStyle);   
    } 

    protected void onDraw(Canvas canvas) { 
     super.onDraw(canvas); 

    } 

    @Override 
    protected void onSizeChanged(int w, int h, int oldw, int oldh) { 
     super.onSizeChanged(w, h, oldw, oldh); 
    } 

    @Override 
    public void setCompoundDrawables(Drawable left, Drawable top, 
      Drawable right, Drawable bottom) { 
     if (left != null) { 
      drawableLeft = left; 
     } 
     if (right != null) { 
      drawableRight = right; 
     } 
     if (top != null) { 
      drawableTop = top; 
     } 
     if (bottom != null) { 
      drawableBottom = bottom; 
     } 
     super.setCompoundDrawables(left, top, right, bottom); 
    } 

    @Override 
    public boolean onTouchEvent(MotionEvent event) { 
     Rect bounds; 
     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); 
      } 

      // this works for left since container shares 0,0 origin with bounds 
      if (drawableLeft != null) { 
       bounds = null; 
       bounds = drawableLeft.getBounds(); 

       int x, y; 
       int extraTapArea = (int) (13 * getResources().getDisplayMetrics().density + 0.5); 

       x = actionX; 
       y = actionY; 

       if (!bounds.contains(actionX, actionY)) { 
        /** Gives the +20 area for tapping. */ 
        x = (int) (actionX - extraTapArea); 
        y = (int) (actionY - extraTapArea); 

        if (x <= 0) 
         x = actionX; 
        if (y <= 0) 
         y = actionY; 

        /** Creates square from the smallest value */ 
        if (x < y) { 
         y = x; 
        } 
       } 

       if (bounds.contains(x, y) && clickListener != null) { 
        clickListener 
          .onClick(DrawableClickListener.DrawablePosition.LEFT); 
        event.setAction(MotionEvent.ACTION_CANCEL); 
        return false; 

       } 
      } 

      if (drawableRight != null) { 

       bounds = null; 
       bounds = drawableRight.getBounds(); 

       int x, y; 
       int extraTapArea = 13; 

       /** 
       * IF USER CLICKS JUST OUT SIDE THE RECTANGLE OF THE DRAWABLE 
       * THAN ADD X AND SUBTRACT THE Y WITH SOME VALUE SO THAT AFTER 
       * CALCULATING X AND Y CO-ORDINATE LIES INTO THE DRAWBABLE 
       * BOUND. - this process help to increase the tappable area of 
       * the rectangle. 
       */ 
       x = (int) (actionX + extraTapArea); 
       y = (int) (actionY - extraTapArea); 

       /**Since this is right drawable subtract the value of x from the width 
       * of view. so that width - tappedarea will result in x co-ordinate in drawable bound. 
       */ 
       x = getWidth() - x; 

       /*x can be negative if user taps at x co-ordinate just near the width. 
       * e.g views width = 300 and user taps 290. Then as per previous calculation 
       * 290 + 13 = 303. So subtract X from getWidth() will result in negative value. 
       * So to avoid this add the value previous added when x goes negative. 
       */ 

       if(x <= 0){ 
        x += extraTapArea; 
       } 

       /* If result after calculating for extra tappable area is negative. 
       * assign the original value so that after subtracting 
       * extratapping area value doesn't go into negative value. 
       */    

       if (y <= 0) 
        y = actionY;     

       /**If drawble bounds contains the x and y points then move ahead.*/ 
       if (bounds.contains(x, y) && clickListener != null) { 
        clickListener 
          .onClick(DrawableClickListener.DrawablePosition.RIGHT); 
        event.setAction(MotionEvent.ACTION_CANCEL); 
        return false; 
       } 
       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; 
    } 

} 

tworzą również interfejs z

public interface DrawableClickListener { 

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

Jeszcze jeśli u potrzeba każda pomoc, komentarz

Ustaw również drawableClickListener na widoku w pliku aktywności.

editText.setDrawableClickListener(new DrawableClickListener() { 


     public void onClick(DrawablePosition target) { 
      switch (target) { 
      case LEFT: 
       //Do something here 
       break; 

      default: 
       break; 
      } 
     } 

    }); 
+0

Przekazałbym również Edittext jako parametr do wywołania zwrotnego. Ale dobra odpowiedź nigdy nie mniej. – st0le

+0

Utworzono niestandardowy EditText. Jeśli dotknę dowolnego miejsca w jego drodze do metody onTouchMovement. ale nigdy nie idzie tu „if (bounds.contains (x, y) && clickListener! = null) { clickListener .onClick (DrawableClickListener.DrawablePosition.RIGHT); event.setAction (MotionEvent.ACTION_CANCEL); return false; } " – user965071

+0

Proszę zobaczyć edytowaną odpowiedź. – Hardik4560

0

proszę skorzystać z poniższego trick:

  • Utwórz przycisk z ikoną obrazu i ustawić jego kolor tła na przezroczyste.
  • Umieść przycisk obrazu na EditText
  • Wdrożenie „onclic'k słuchacza przycisku, aby wykonać czynność
+0

co się stanie, jeśli zwiększy się rozmiar editText ?, co jeśli mam wiele editText, który wymaga tego, co zwykle się zdarza. – Hardik4560

+0

Musisz zrozumieć pytanie! On/ona nie pyta o alternatywne rozwiązanie. – Nizzy

+0

Problem z tym podejściem polega na tym, że rozpada się, gdy tylko zaczniesz zmieniać rozmiar tekstu w EditText. Można by pomyśleć, że to tylko po stronie programisty, ale nie jest tak daleko, jak urządzenia mają rozmiar tekstu w ustawieniach. Można tego uniknąć za pomocą dp zamiast sp w EditText, ale to tylko pogarsza sprawę. Inne problemy to obsługa multilinii EditTexts – Sotti

6

Nie masz dostępu do prawego obrazu o ile mi wiadomo, chyba że zastąpić zdarzenie onTouch. Proponuję użyć RelativeLayout, z jednym editText i jednym imageView i ustaw OnClickListener nad widzenia obrazu, jak poniżej:

<RelativeLayout 
     android:id="@+id/rlSearch" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:background="@android:drawable/edit_text" 
     android:padding="5dip" > 

     <EditText 
      android:id="@+id/txtSearch" 
      android:layout_width="match_parent" 

      android:layout_height="wrap_content" 
      android:layout_centerVertical="true" 
      android:layout_toLeftOf="@+id/imgSearch" 
      android:background="#00000000" 
      android:ems="10"/> 

     <ImageView 
      android:id="@+id/imgSearch" 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" 
      android:layout_alignParentRight="true" 
      android:layout_centerVertical="true" 
      android:src="@drawable/btnsearch" /> 
    </RelativeLayout> 
+0

Problem z tym podejściem polega na tym, że rozpada się, gdy tylko zaczniesz zmieniać rozmiar tekstu w EditText. Można by pomyśleć, że to tylko po stronie programisty, ale nie jest tak daleko, jak urządzenia mają rozmiar tekstu w ustawieniach. Można tego uniknąć za pomocą dp zamiast sp w EditText, ale to tylko pogarsza sprawę. Innymi problemami są rzeczy takie jak obsługa wielowierszowego EditTexts – Sotti

-1

Wiem, że jest dość stary, ale ostatnio musiałem zrobić coś bardzo podobnego i zaproponowałem znacznie prostsze rozwiązanie.

To sprowadza się do następujących kroków:

  1. Utwórz układ XML zawierający EditText i obrazowy
  2. Podklasa FrameLayout i napompować układ XML
  3. Dodaj kod dla słuchacza kliknięć i wszelkie inne zachowanie, które chcesz ... nie martwiąc się o pozycje kliknięcia lub inny nieporządny kod.

Zobacz ten post dla pełnego Przykład: Handling click events on a drawable within an EditText

21

Zostało już odpowiedział, ale spróbował innego sposobu, aby to prostsze.

Pomysł korzysta kładąc ImageButton po prawej EditText i posiadające ujemny margines do niego tak, że EditText wpada do ImageButton dzięki czemu wyglądają jak przycisk jest w EditText.

enter image description here

<LinearLayout 
     android:layout_width="match_parent" 
     android:layout_height="wrap_content" 
     android:orientation="horizontal"> 
     <EditText 
      android:id="@+id/editText" 
      android:layout_weight="1" 
      android:layout_width="0dp" 
      android:layout_height="wrap_content" 
      android:hint="Enter Pin" 
      android:singleLine="true" 
      android:textSize="25sp" 
      android:paddingRight="60dp" 
      /> 
     <ImageButton 
      android:id="@+id/pastePin" 
      android:layout_marginLeft="-60dp" 
      style="?android:buttonBarButtonStyle" 
      android:paddingBottom="5dp" 
      android:src="@drawable/ic_action_paste" 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" /> 
    </LinearLayout> 

Ponadto, jak wykazano powyżej, można użyć paddingRight podobnej szerokości w EditText, jeśli nie chcesz, aby tekst w nim będzie przelatywał nad ImageButton.

Podejrzewam rozmiar marginesu za pomocą projektanta układu Android-studio i wygląda on podobnie we wszystkich rozmiarach ekranu. Albo możesz obliczyć szerokość ImageButton i ustawić margines programowo.

+0

To jest inteligentna praca –

+0

To proste rzeczy, które działają najlepiej. – DariusL

+1

to jest praca zbędna dla pojedynczego losowania –

167

Proste rozwiązanie, metod mechanicznych że Android został już podany, zamiast wymyślania wheeeeeeeeeel :-)

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

Błąd: java.lang.ArrayIndexOutOfBoundsException: length = 4; index = 2130837593 – user2273146

+1

@ user2273146 jeśli twoja długość to 4, to twój indeks musi wynosić 3. ponieważ długość zaczyna się od 1, nie ma długości 0, ale jeśli długość wynosi 1 to indeks jest 0 –

+3

Pracował dla mnie. Oto kod naciśnięcia lewej ikony ... if (event.getRawX() <= (editComment.getCompoundDrawables() [DRAWABLE_LEFT] .getBounds(). Width())) – kwh

Powiązane problemy