我EditText
使用以下XML 在窗口小部件中添加了文本右侧的图像:
但我想清除EditText
点击嵌入图像的时间.我怎样才能做到这一点?
实际上你不需要扩展任何类.假设我有一个带有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()))
非常非常好,感谢所有为此次讨论做出贡献的人.因此,如果您不想处理扩展课程的不便,您可以执行以下操作(仅适用于正确的绘图)
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); }
考虑以下.它不是最优雅的解决方案,但它可以工作,我只是测试它.
创建自定义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(); } }
将布局XML更改为此(com.example
实际项目包名称在哪里):
最后,将此(或类似的东西)添加到您的活动中:
… CustomEditText et = (CustomEditText) this.findViewById(R.id.txtsearch); …
我可能对嵌套drawable的触摸边界的计算有点偏,但你明白了.
我希望这有帮助.
我创建了一个有用的抽象类DrawableClickListener,它实现了OnTouchListener.
除了DrawableClickListener类之外,我还创建了4个额外的抽象类,它们扩展了DrawableClickListener类并处理了可绘制区域的正确象限点击.
LeftDrawableClickListener
TopDrawableClickListener
RightDrawableClickListener
BottomDrawableClickListener
要考虑一下
要考虑的一件事是,如果这样做,图像不会调整大小; 因此,在放入res/drawable文件夹之前,必须正确缩放图像.
如果定义包含ImageView和TextView的LinearLayout,则操作所显示图像的大小要容易得多.
activity_my.xml
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 "fuzz" 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. *
* use one of the values: * DrawableOnTouchListener.DRAWABLE_INDEX_* */ 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. *
* use one of the values: * DrawableOnTouchListener.DRAWABLE_INDEX_* * @param fuzzOverride * The number of pixels of "fuzz" 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 *true
if the listener has consumed the event; *false
otherwise. * */ public abstract boolean onDrawableClick(); /* PUBLIC CLASSES */ /** * This class can be used to define a listener for a LEFT 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 "fuzz" 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 TOP 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 "fuzz" 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 RIGHT 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 "fuzz" 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 BOTTOM 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 "fuzz" 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; } } }
它非常简单.假设你在EditText'txtsearch'的左侧有一个drawable.以下将做到这一点.
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; } });
如果你想要正确的drawable改变if语句:
if(event.getRawX() >= txtsearch.getRight() - txtsearch.getTotalPaddingRight())
同样,您可以为所有复合drawables执行此操作.
txtsearch.getTotalPaddingTop() txtsearch.getTotalPaddingBottom()
此方法调用返回该侧的所有填充,包括任何drawable.您甚至可以将它用于TextView,Button等.
点击这里从android开发者网站获取参考.
最后一个贡献的使用contains(x,y)
不会直接对结果起作用getBounds()
(除非巧合,使用"左"drawables).该getBounds
方法仅提供Rect
使用原点0,0标准化的可绘制项的定义点 - 因此,您实际上需要对原始帖子进行数学运算,以确定点击是否位于可绘制区域中的可绘制区域中.包含EditText的尺寸,但更改为top,right,left等.或者您可以描述一个Rect
实际上相对于其在EditText
容器中的位置并使用的坐标contains()
,尽管最后您正在进行相同的数学运算.
将它们组合起来两者都为您提供了一个非常完整的解决方案,我只添加了一个实例属性consumesEvent
,允许API用户决定是否应该通过使用其结果进行设置来传递click事件ACTION_CANCEL
.
此外,我不明白为什么bounds
和actionX
,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; } }
我认为如果我们使用一些技巧会更容易:)
使用您的图标创建一个图像按钮,并将其背景颜色设置为透明.
将图像按钮放在EditText上,然后放在右侧
实现按钮的onclick监听器以执行您的功能
完成
通过RyanM扩展这个想法,我创建了一个更灵活的版本,它支持所有可绘制类型(顶部,底部,左侧,右侧).虽然下面的代码扩展了TextView,但是将它改编为EditText只是用"extends EditText"交换"extends TextView"的情况.从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; } }}
ps:如果没有设置监听器,则触摸TextView将导致NullPointerException.您可能希望在代码中添加更多偏执狂.
它为我工作,
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; } });