Android中EditText无Drawable时OnTouchListener失效问题及清除图标需求
解决EditText清除图标无文本时隐藏且OnTouchListener失效的问题
嘿,我来帮你搞定这个EditText清除图标的问题!你遇到的痛点其实很常见——当你把右侧Drawable设为0的时候,OnTouchListener就因为没有可触发的Drawable区域直接失效了。下面给你两种靠谱的解决思路,直接就能用:
方案一:动态切换Drawable+透明占位符
这个方案的核心是始终保持右侧有一个Drawable(哪怕是透明的),这样触摸区域就不会消失,同时根据文本内容切换图标可见性。
步骤1:准备资源
先准备两个Drawable:
- 清除图标:比如
ic_clear.xml(你的清除按钮图标) - 透明占位符:
ic_transparent.xml(一个完全透明的shape,用来占位)
步骤2:设置TextWatcher监听文本变化
通过文本监听来控制图标的显示和隐藏:
txtBookingCode.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) { // 根据文本长度切换右侧Drawable if (s.length() > 0) { // 显示清除图标 txtBookingCode.setCompoundDrawablesWithIntrinsicBounds( 0, 0, R.drawable.ic_clear, 0); } else { // 显示透明占位符,维持触摸区域 txtBookingCode.setCompoundDrawablesWithIntrinsicBounds( 0, 0, R.drawable.ic_transparent, 0); } } @Override public void afterTextChanged(Editable s) {} });
步骤3:完善OnTouchListener逻辑
现在不管有没有文本,右侧都有Drawable占位,触摸事件能正常触发,我们只需要判断触摸位置和文本状态:
txtBookingCode.setOnTouchListener((v, event) -> { // 获取右侧Drawable Drawable rightDrawable = txtBookingCode.getCompoundDrawables()[2]; if (rightDrawable == null) { return false; } // 只处理抬起事件 if (event.getAction() == MotionEvent.ACTION_UP) { int drawableWidth = rightDrawable.getIntrinsicWidth(); // 计算Drawable的触摸范围:EditText右边界 - Drawable宽度 - 内边距 boolean isTouchOnDrawable = event.getRawX() >= (txtBookingCode.getRight() - drawableWidth - txtBookingCode.getPaddingRight()); // 只有当文本不为空且触摸在Drawable区域时,执行清除操作 if (isTouchOnDrawable && txtBookingCode.getText().length() > 0) { txtBookingCode.setText(""); return true; // 消费事件,避免传递给其他控件 } } return false; });
方案二:自定义EditText封装逻辑
如果多个页面需要这个功能,自定义EditText会更省心,把所有逻辑封装进去,直接在布局里使用即可:
public class ClearableEditText extends EditText { private Drawable clearDrawable; public ClearableEditText(Context context) { super(context); init(); } public ClearableEditText(Context context, AttributeSet attrs) { super(context, attrs); init(); } public ClearableEditText(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } private void init() { // 初始化清除图标 clearDrawable = getResources().getDrawable(R.drawable.ic_clear, getContext().getTheme()); clearDrawable.setBounds(0, 0, clearDrawable.getIntrinsicWidth(), clearDrawable.getIntrinsicHeight()); // 默认隐藏清除图标(显示透明占位符) setClearIconVisible(false); // 文本变化监听 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) { setClearIconVisible(s.length() > 0); } @Override public void afterTextChanged(Editable s) {} }); // 触摸事件处理 setOnTouchListener((v, event) -> { Drawable rightDrawable = getCompoundDrawables()[2]; if (rightDrawable == null) { return false; } if (event.getAction() == MotionEvent.ACTION_UP) { int drawableWidth = rightDrawable.getIntrinsicWidth(); boolean isTouchOnDrawable = event.getX() > (getWidth() - getPaddingRight() - drawableWidth); if (isTouchOnDrawable && getText().length() > 0) { setText(""); return true; } } return false; }); } // 控制清除图标显示/隐藏 private void setClearIconVisible(boolean visible) { Drawable rightDrawable = visible ? clearDrawable : getResources().getDrawable(R.drawable.ic_transparent, getContext().getTheme()); setCompoundDrawables(getCompoundDrawables()[0], getCompoundDrawables()[1], rightDrawable, getCompoundDrawables()[3]); } }
然后在布局里直接使用:
<com.yourpackage.ClearableEditText android:id="@+id/txtBookingCode" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="输入预订码"/>
为什么之前的方法失效?
核心原因:当你调用setCompoundDrawablesWithIntrinsicBounds(0,0,0,0)时,右侧Drawable会被置为null,系统不会为不存在的Drawable分配触摸区域,所以你的OnTouchListener自然不会响应触摸事件。用透明占位符就能完美解决这个问题,既保持了触摸区域,又不会让用户看到多余的图标。
内容的提问来源于stack exchange,提问作者Om Prakash Gupta
相关产品推荐
相关产品推荐

