EditText 내 드로어 블에서 클릭 이벤트 처리


239

EditText다음 XML을 사용하여 위젯 의 텍스트 오른쪽 이미지를 추가했습니다 .

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

그러나 EditText포함 된 이미지를 클릭 할 때 를 지우고 싶습니다 . 어떻게해야합니까?


답변:


358

실제로 수업을 연장 할 필요는 없습니다. drawableRight가있는 EditText editComment가 있다고 가정 해 봅시다.

editComment.setOnTouchListener(new OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        final int DRAWABLE_LEFT = 0;
        final int DRAWABLE_TOP = 1;
        final int DRAWABLE_RIGHT = 2;
        final int DRAWABLE_BOTTOM = 3;

        if(event.getAction() == MotionEvent.ACTION_UP) {
            if(event.getRawX() >= (editComment.getRight() - editComment.getCompoundDrawables()[DRAWABLE_RIGHT].getBounds().width())) {
                // your action here

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

우리 getRawX() 부모가 아닌 화면상의 실제 터치 위치를 원하기 때문에.

왼쪽 클릭을 얻으려면

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

2
@ user2848783 왼쪽 드로어 블에서 이것을 설정하는 방법은 무엇입니까?
Qadir Hussain

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

4
한 가지 참고 사항 : "return false"를 바꾸십시오. "참으로 돌아가다" 그렇지 않으면 ACTION_DOWN 후-> ACTION_UP이 시작되지 않습니다.
tomurka

9
패딩을 추가 getRight()하면 TextView의 권리를 얻는 것뿐만 아니라 패딩을 계산해야합니다 . 패딩이 있으면 드로어 블의 권리가 아닙니다. 명세서 - editComment.getPaddingRight()끝에 추가하면 효과 if가 있습니다.
kassim

21
EditText의 부모가 화면의 왼쪽에 정렬되어 있지 않으면 작동하지 않습니다. event.getRawX () 대신 event.getX ()를 사용하고 editText.getRight () 대신 editText.getWidth ()를 사용해야합니다.
Fletcher Johns

85

이 토론에 기여한 모든 사람에게 감사합니다. 따라서 클래스를 확장하는 데 불편을 겪고 싶지 않으면 다음을 수행 할 수 있습니다 (올바른 드로어 블에만 구현 됨)

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

그리고 @Mark의 답변을 기반으로 한 본 리스너 구현이 있습니다.

public abstract class RightDrawableOnTouchListener implements OnTouchListener {
    Drawable drawable;
    private int fuzz = 10;

    /**
     * @param keyword
     */
    public RightDrawableOnTouchListener(TextView view) {
        super();
        final Drawable[] drawables = view.getCompoundDrawables();
        if (drawables != null && drawables.length == 4)
            this.drawable = drawables[2];
    }

    /*
     * (non-Javadoc)
     * 
     * @see android.view.View.OnTouchListener#onTouch(android.view.View, android.view.MotionEvent)
     */
    @Override
    public boolean onTouch(final View v, final MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN && drawable != null) {
            final int x = (int) event.getX();
            final int y = (int) event.getY();
            final Rect bounds = drawable.getBounds();
            if (x >= (v.getRight() - bounds.width() - fuzz) && x <= (v.getRight() - v.getPaddingRight() + fuzz)
                    && y >= (v.getPaddingTop() - fuzz) && y <= (v.getHeight() - v.getPaddingBottom()) + fuzz) {
                return onDrawableTouch(event);
            }
        }
        return false;
    }

    public abstract boolean onDrawableTouch(final MotionEvent event);

}

3
올바른 위치를 얻으려면 v.getLeft ()를 x에, v.getTop ()을 y에 추가해야합니다.
안드레

3
실제로는로 대체해야 v.getRight()합니다 v.getWidth().
빠른

2
퍼즈 팩터는 DPI에 따라 확장되어야하며 ldpi의 10px는 xxhdpi의 10px와 완전히 다릅니다.
RaB

4
퍼즈 란? 명확히하십시오.
Юрій Мазуревич

1
fuzz탭핑 가능 영역을 효과적으로 조금 크게 만들어 작은 드로어 블을 쉽게 탭하는 것처럼 보입니다 .
금지 지오 엔지니어링

28

다음을 고려하세요. 가장 우아한 솔루션은 아니지만 작동하지만 방금 테스트했습니다.

  1. 사용자 정의 EditText클래스를 작성하십시오 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. 레이아웃 XML을 이것으로 변경하십시오 ( com.example실제 프로젝트 패키지 이름은 어디에 있습니까 ).

    <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. 마지막으로, 당신의 활동에 이것을 추가하십시오 :

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

중첩 된 드로어 블의 터치 범위 계산으로 약간 벗어날 수 있지만 아이디어를 얻습니다.

이게 도움이 되길 바란다.


실제로, MotionEvent를 수정하는 것은 권장하지 않는 방법으로 여러 플랫폼에서 작동하지 않을 수있는 정의되지 않은 동작으로 이어질 수 있으므로 더 나은 솔루션은 stackoverflow.com/a/6235602
Giulio Piancastelli

@RyanM, TextView대신에 사용 했습니다 EditText. 코드를 가져 와서 TextView(아이콘이 아니라에서 공백을 클릭하면 TextView) 메소드 onTouchEvent(MotionEvent event)가 호출됩니다. 따라서 다음 과 같은 추가 클래스없이 OnClickListener평소에 구현할 수 있습니다.TextViewCustomEditText
Maksim Dmitriev

@RyanM, 대신 사용 this.getRight()-rBounds.width()하지 않는 이유는 this.getMeasuredWidth() - this.getCompoundPaddingRight()무엇입니까? 드로어 블의 패딩을 처리하고 드로어 블의 바인딩을 제거하지 않습니까?
Vino

@RyanM 크로스 버튼 클릭 이벤트의 터치시 이미지를 변경하는 방법은 무엇입니까?
Qadir Hussain

EditText막대 사탕 사전 장치에서 appcompat를 사용할 때 사용자 정의 버전은 적절한 위젯 색조를 지원하지 않습니다. 를 사용하여 AppCompatEditText사용자 정의 글고의 부모 클래스로
Tomask

24

OnTouchListener 를 구현 하는 유용한 추상 클래스 DrawableClickListener 를 만들었습니다. .

받는 사람 또한 DrawableClickListener의 클래스, 나는 또한 확장 4 개 개의 추가 추상 클래스 생성 DrawableClickListener의 클래스를 올바른 사분면의 그리기 가능 영역의 클릭을 처리합니다.

  • LeftDrawableClickListener
  • TopDrawableClickListener
  • RightDrawableClickListener
  • BottomDrawableClickListener

고려할 사항

한 가지 고려해야 할 사항은이 방법으로 수행하면 이미지 크기가 조정되지 않는다는 것입니다. 따라서 이미지를 res / drawable 폴더 에 배치하기 전에 이미지의 크기를 올바르게 조정해야합니다 .

ImageViewTextView를 포함하는 LinearLayout 을 정의하면 표시되는 이미지의 크기를 조작하는 것이 훨씬 쉽습니다.


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

매우 간단합니다. 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;
    }
});

올바른 드로어 블을 원하면 if 문을 다음과 같이 변경하십시오.

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

마찬가지로 모든 복합 드로어 블에 대해서도 가능합니다.

txtsearch.getTotalPaddingTop()
txtsearch.getTotalPaddingBottom()

이 메소드 호출은 드로어 블을 포함하여 해당 측면의 모든 패딩을 반환합니다. TextView, Button 등에서도 사용할 수 있습니다.

안드로이드 개발자 사이트에서 참조 하려면 여기 를 클릭 하십시오 .


1
나는 이것이 어디에서나 true가 반환되는 부분을 제외하고는 좋은 대답이라고 생각합니다. 이벤트를 사용해야 할 때만 (터치 제스처가 올바른 영역에서 발생) 참을 반환하는 것이 좋습니다.
Bianca Daniciuc

12

우리가 몇 가지 트릭을 사용하면 훨씬 쉽다고 생각합니다. :)

  1. 아이콘 으로 이미지 버튼 을 만들고 배경색을 투명하게 설정하십시오 .
  2. EditText에 이미지 버튼을 넣고 오른쪽에 coz
  3. 버튼의 onclick 리스너를 구현하여 기능을 실행하십시오.

끝난


1
RelativeLayout적절한 포지셔닝을 달성하는 데 사용 되며 다른 솔루션보다 덜 복잡하고 유지해야 할 코드가 훨씬 적습니다.
C0D3LIC1OU5 2016

12

마지막 기여 contains(x,y)getBounds()"왼쪽"드로어 블을 사용할 때를 제외하고 는 결과에 직접 영향을 미치지 않습니다 . 이 getBounds방법 Rect은 0,0에서 원점으로 정규화 된 드로어 블 항목 의 정의 점 만 제공 하므로 클릭이 드로어 블의 영역에 있는지 확인하려면 원래 게시물의 수학을 수행해야 EditText의 치수를 포함하지만 상단, 오른쪽, 왼쪽 등으로 변경하십시오. 또는 Rect실제로 동일한 계산을 수행하지만 EditText컨테이너 의 위치를 ​​기준으로 좌표가있는를 설명 하고 사용할 contains()수 있습니다.

둘 다 결합하면 매우 완벽한 솔루션 consumesEvent을 얻을 수 있으며 API 사용자가 결과를 사용하여 클릭 이벤트를 전달 해야하는지 여부를 결정할 수 있는 인스턴스 속성 만 추가했습니다.ACTION_CANCEL .

또한, 나는 왜 볼 수 boundsactionX,actionY 값은 인스턴스가 스택에 단지 지역보다는 속성입니다.

위의 내용을 기반으로 한 구현에서 나온 컷 아웃은 다음과 같습니다. false를 반환해야하는 이벤트를 올바르게 사용하는 문제를 해결합니다. "퍼지"요소를 추가합니다. EditText필드 의 음성 제어 아이콘 사용 사례 에서 클릭하기가 어려워서 퍼즈가 드로어 블을 클릭하는 것으로 간주되는 유효 범위를 증가시킵니다. 나를 15위해 잘 일했다. 난 단지 필요 drawableRight내가 다른 사람에 수학을 연결하지 않은 일부 공간을 절약 할 수 있도록,하지만 당신은 아이디어를 참조하십시오.

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

RyanM의 아이디어를 확장하여 모든 드로어 블 유형 (상단, 하단, 왼쪽, 오른쪽)을 지원하는보다 유연한 버전을 만들었습니다. 아래 코드는 TextView를 확장하지만 EditText에 맞게 수정하면 "extends TextView"를 "extends EditText"로 교체하는 경우입니다. XML에서 위젯을 인스턴스화하는 것은 위젯 이름을 표시하는 RyanM의 예에서와 동일합니다.


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는 다음과 같이 간단합니다.

public interface DrawableClickListener {

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

그리고 실제 구현 :

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

추신 : 리스너를 설정하지 않으면 TextView를 터치하면 NullPointerException이 발생합니다. 코드에 편집증을 더 추가 할 수 있습니다.


코드가 작동하지 않는 것 같습니다. 방금 테스트 한 결과 드로어 블을 만지면 아무 일도 일어나지 않습니다.
Thiago

8

코 틀린은 각 수업을 새로운 방법으로 확장 할 수있는 훌륭한 언어입니다. 오른쪽 클릭 가능한 클릭을 잡을 수있는 EditText 클래스에 대한 새로운 메소드를 소개합니다.

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

사용자가 오른쪽 드로어 블을 클릭하면 호출되는 인수로 콜백 함수가 필요하다는 것을 알 수 있습니다.

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

7

나를 위해 일하는

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

적중 사각형의 시작을 결정할 때 텍스트 편집을 위해 오른쪽 여백을 빼야합니다.
farid_z

4

나는 이것이 아주 오래되었다는 것을 알고 있지만 최근에는 비슷한 것을해야했습니다 ...이 얼마나 어려운지를 보았을 때 훨씬 간단한 해결책을 찾았습니다.

  1. EditText 및 이미지가 포함 된 XML 레이아웃 만들기
  2. 서브 클래스 FrameLayout 및 XML 레이아웃 확장
  3. 클릭 리스너 및 원하는 기타 동작에 대한 코드 추가

필자의 경우 버튼으로 텍스트를 지울 수있는 EditText가 필요했습니다. SearchView처럼 보이기를 원했지만 여러 가지 이유로 해당 클래스를 사용하고 싶지 않았습니다. 아래 예제는 어떻게이 작업을 수행했는지 보여줍니다. 포커스 변경과 관련이 없더라도 원칙은 동일하며 실제 작업 코드를 게시하는 것이 의도 한대로 정확하게 작동하지 않을 수있는 예제를 작성하는 것보다 더 유리할 것이라고 생각했습니다.

여기 내 레이아웃이 있습니다 : 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>

그리고 그 레이아웃을 부 풀리는 클래스는 다음과 같습니다. 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;
        }
    }
}

질문에 따라이 답변을 더 많이 만들려면 다음 단계를 수행해야합니다.

  1. 드로어 블 리소스를 원하는대로 변경하십시오 ... 제 경우에는 회색 X였습니다
  2. 편집 텍스트에 포커스 변경 리스너 추가 ...

3

드로어 블이 왼쪽에 있으면 도움이됩니다. (RTL 레이아웃 작업의 경우)

 editComment.setOnTouchListener(new OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            final int DRAWABLE_LEFT = 0;
            final int DRAWABLE_TOP = 1;
            final int DRAWABLE_RIGHT = 2;
            final int DRAWABLE_BOTTOM = 3;

            if(event.getAction() == MotionEvent.ACTION_UP) {
                if (event.getRawX() <= (searchbox.getLeft() + searchbox.getCompoundDrawables()[DRAWABLE_LEFT].getBounds().width())) {
                                     // your action here

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

이것은 절대 위치 "getRawX"를 상대 위치 "getRight"와 혼합합니다. editText에서 오른쪽 또는 왼쪽 여백을 설정하면 클릭이 잘못된 좌표에서 트리거 될 때 이것이 어떻게 끊어 지는지 알 수 있습니다.
Sotti

3

다음 코드를 복사하여 붙여 넣기 만하면됩니다.

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
이것은 나를 위해 일했지만 getRawX () 대신 getX ()를 사용해야했습니다. getRawX ()는 뷰가 화면의 왼쪽 가장자리에있는 경우에만 작동한다고 생각합니다.
Glenn

1
위치 계산이 잘못되었습니다. 절대 좌표 "getRawX ()"를 "getRight ()"와 같은 상대 좌표와 혼합하고 있습니다.
Sotti

3

이전 솔루션 중 어느 것도 Xamarin Android 에서 작동하지 않았습니다 . 다음을 사용하여 올바른 드로어 블 클릭 리스너를 작동시킬 수있었습니다.

다음과 같은 OnEditTextTouch이벤트 리스너를 작성하십시오 .

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

터치 이벤트를 구독하십시오.

_autoCompleteTextViewSearch.Touch += OnEditTextTouch;

2

모두 훌륭하지만 왜 그렇게 단순하게 만들지 않겠습니까?

나는 그렇게 오래 전에도 직면했습니다 ... Android touchlistiner는 훌륭하게 작동하지만 사용에는 제한이 있습니다.

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

여기에 이미지 설명을 입력하십시오 이제 ImageClick 리스너 또는 이벤트를 만들고 텍스트로 원하는 것을 할 수 있습니다. 이 edittext_round_corners.xml 파일

<item android:state_pressed="false" android:state_focused="false">
    <shape>
        <gradient
            android:centerY="0.2"
            android:startColor="@color/colorAccent"
            android:centerColor="@color/colorAccent"
            android:endColor="@color/colorAccent"
            android:angle="270"
            />
        <stroke
            android:width="0.7dp"
            android:color="@color/colorAccent" />
        <corners
            android:radius="5dp" />
    </shape>
</item>


이 방법의 문제점은 EditText에서 텍스트 크기를 변경하기 시작하자마자 분리된다는 것입니다. 개발자 측에서만 생각할 수도 있지만 장치의 설정에 텍스트 크기가있는 한 그렇지 않습니다 .EditText에서 sp 대신 dp를 사용하여이를 피할 수는 있지만 상황이 악화됩니다. 다른 문제는 여러 줄로 된 EditText 처리와 같은 것입니다.
Sotti

나는 그것을 여러 줄 검색에 사용한 적이 없으므로 죄송합니다.이 문제가 나타날 것이라고 생각하지 않았습니다. 다중 회선을 차단하는 것이 도움이 될 것입니다. 앱의 스크린 샷을 첨부하거나 어떻게되는지 볼 수 있습니까? 그리고 나는 그것을 해결하려고 노력할 것이고 아마도 나중에 사용할 수 있도록 당신을 도울 것입니다 (이 코드를 수정하십시오). 감사.
Jevgenij Kononov

복제하기가 매우 쉽고 2 줄을 추가하자마자 레이아웃 미리보기에서도 발생합니다.
Sotti

의 배경은 EditText이어야합니다 android:background="@android:color/transparent".
CoolMind

1

편집 텍스트 오른쪽에 ImageButton을 두는 것이 좋습니다. 편집 텍스트와 겹치도록 음수 레이아웃 여백을 제공하십시오. ImageButton에서 리스너를 설정하고 작업을 수행하십시오.


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>

이 방법의 문제점은 EditText에서 텍스트 크기를 변경하기 시작하자마자 분리된다는 것입니다. 개발자 측에서만 생각할 수도 있지만 장치의 설정에 텍스트 크기가있는 한 그렇지 않습니다 .EditText에서 sp 대신 dp를 사용하여이를 피할 수는 있지만 상황이 악화됩니다. 다른 문제는 여러
줄로 된

1

왼쪽 드로어 블 클릭 리스너 용

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

이것은 절대 위치 "getRawX"를 상대 위치 "getRight"와 혼합합니다. editText에서 오른쪽 또는 왼쪽 여백을 설정하면 클릭이 잘못된 좌표에서 트리거 될 때 이것이 어떻게 끊어 지는지 알 수 있습니다.
Sotti

1

복합 드로어 블은 클릭 할 수 없습니다. 수평 LinearLayout에서 별도의 뷰를 사용하고 클릭 핸들러를 사용하는 것이 더 깨끗합니다.

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

이 방법의 문제점은 EditText에서 텍스트 크기를 변경하기 시작하자마자 분리된다는 것입니다. 개발자 측에서만 생각할 수도 있지만 장치의 설정에 텍스트 크기가있는 한 그렇지 않습니다 .EditText에서 sp 대신 dp를 사용하여이를 피할 수는 있지만 상황이 악화됩니다. 다른 문제는 여러 줄로 된 EditText 처리와 같은 것입니다.
Sotti

1

괴물 같은 클릭 처리를 구현하고 싶지 않은 사람. 로도 같은 결과를 얻을 수 있습니다 RelativeLayout. 이를 통해 드로어 블의 위치를 ​​자유롭게 처리 할 수 ​​있습니다.

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

ImageView위치는 사용 하는 위치와 동일하며 drawableEnd모든 터치 리스너 처리가 필요하지 않습니다. 의 클릭 리스너 만 ImageView있으면됩니다.


이 방법의 문제점은 EditText에서 텍스트 크기를 변경하기 시작하자마자 분리된다는 것입니다. 개발자 측에서만 생각할 수도 있지만 장치의 설정에 텍스트 크기가있는 한 그렇지 않습니다 .EditText에서 sp 대신 dp를 사용하여이를 피할 수는 있지만 상황이 악화됩니다. 다른 문제는 여러
줄로 된

1

이것은 나를 위해 작동합니다 :) 이것이 당신을 도울 수 있습니까?

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

이것은 절대 위치 "getRawX"를 상대 위치 "getRight"와 혼합합니다. editText에서 오른쪽 또는 왼쪽 여백을 설정하면 클릭이 잘못된 좌표에서 트리거 될 때 이것이 어떻게 끊어 지는지 알 수 있습니다.
Sotti

내가 편집 텍스트에 오른쪽 여백을 추가 한, 내 코드는 여전히 완벽하게 작동
zohaib Khaliq가

1

나는 여러 가지 해결책을 보았지만 그중 어느 것에도 확신하지 못했습니다. 매우 복잡하거나 너무 단순합니다 (재사용 불가능).

이것은 현재 내가 가장 좋아하는 접근법입니다.

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

그리고 이것은 재사용 가능한 터치 리스너입니다.

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

여기서 요점을 볼 수 있습니다.


1

드로어 블 오른쪽, 왼쪽, 위, 아래를 클릭하려면 아래 코드를 따르십시오.

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에서 구현했습니다.

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

여기 내 간단한 솔루션입니다, 단지 배치 ImageButton를 통해 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

드로어 블 왼쪽에 대한 방법을 제안하고 싶습니다! 이 코드를 사용해 보았습니다.

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

이것은 절대 위치 "getRawX"를 상대 위치 "getRight"와 혼합합니다. editText에서 오른쪽 또는 왼쪽 여백을 설정하면 클릭이 잘못된 좌표에서 트리거 될 때 이것이 어떻게 끊어 지는지 알 수 있습니다.
Sotti

0

Mono.Droid (Xamarin)에서 @aristo_sh 답변을 구현했습니다. 익명 익명 메서드이기 때문에 true 또는 false를 반환 할 수 없으므로 e.Event.Handled를 가져와야합니다. 클릭시 키보드가 숨겨져 있습니다.

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 복합 드로어 블 클릭 앤 터치 이벤트 처리를위한 일반화 된 솔루션 공유

먼저 터치 이벤트 핸들러가 필요합니다 :

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

이제 다음과 같이 원하는 TextView의 모든 드로어 블에서 터치 이벤트를 처리 할 수 ​​있습니다.

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

클릭에만 관심이 있습니까? MotionEvent 액션으로 필터링하십시오.

/**
 * Handles compound drawable click events.
 * @see TextView#getCompoundDrawables()
 * @see TextView#setCompoundDrawablesRelativeWithIntrinsicBounds(int, int, int, int)
 * @see CompoundDrawableTouchListener
 */
public abstract class CompoundDrawableClickListener extends CompoundDrawableTouchListener {

    /**
     * Default constructor
     */
    public CompoundDrawableClickListener() {
        super();
    }

     /**
     * Constructor with fuzz
     * @param fuzz desired fuzz in px
     */
    public CompoundDrawableClickListener(int fuzz) {
        super(fuzz);
    }

    @Override
    protected void onDrawableTouch(View v, int drawableIndex, Rect drawableBounds, MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_UP) onDrawableClick(v, drawableIndex);
        return true;
    }

    /**
     * Compound drawable touch-event handler
     * @param v wrapping view
     * @param drawableIndex index of compound drawable which recicved the event
     */
    protected abstract void onDrawableClick(View v, int drawableIndex);
}

다시 한 번 TextView의 컴파운드 드로어 블에 대한 클릭을 쉽게 처리 할 수 ​​있습니다.

textView1.setOnTouchListener(new CompoundDrawableClickListener() {
            @Override
            protected void onDrawableClick(View v, int drawableIndex) {
                switch(v.getId()) {
                    case R.id.textView1:
                        switch(drawableIndex) {
                            case CompoundDrawableTouchListener.RIGHT:
                                doStuff();
                                break;
                        }
                        break;
                }
            }
        });

내가 한 것처럼 당신이 그것을 좋아 바랍니다. 변경 사항이 있으면 여기 및 관련 요지 에서 업데이트하도록 노력하겠습니다 .


0

사용자 정의 EditText 대신 간단한 사용자 정의 터치 리스너 클래스를 만들었습니다.

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가 비어 있으면 드로어 블이 없습니다. EditText를 지우기 위해 편집을 시작하면 드로어 블이 표시됩니다.

터치 리스너 만 설정하면됩니다

mEditText.setOnTouchListener (새 MyTouchListener (mEditText));


TouchListener가 드로어 블 가시성 및 명확한 동작 자체를 처리한다는 것은 약간 혼란 스럽습니다. 그것은 터치 리스너의 책임이 아니며 클래스의 이름이 잘못되었습니다. 또한 상대 위치를 계산할 때 방정식에서 여백을 제거 할 필요는 없습니다. getRight-너비가 수행합니다.
Sotti
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.