输入框设置右侧清空输入框图标(原生drawableEnd图标方法)
功能需求
- 当输入框没有输入时,不显示清除图标
- 当有字符输入时,显示清除图标
- 失去焦点时隐藏图标,取得焦点并且输入框中有字符时显示图标
- 点击清除图标时清空输入框,并且隐藏图标
实现过程
原生EditText有自带drawableEnd属性,即可以设置一个右侧图标(其实有drawableStart, drawableTop, drawableEnd, drawableBottom四种属性,分别对应左、上、右、下侧图标)。但是Google并没有对drawableEnd图标提供相应的点击事件,点击图标无法执行相关操作。
针对上面的需求,大多数人都选择自定义EditText实现,但个人觉得比较麻烦。一番搜索之后发现一个方法,可以通过判断EditText的点击位置,即如果是图标所在位置,就执行相关操作,以此来实现上述需求。
EditText点击位置监听
public class InputClearOnTouchListener implements View.OnTouchListener {
private EditText editText;
public InputClearOnTouchListener(EditText editText){
this.editText = editText;
}
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
//获取右侧图标
Drawable drawableRight = editText.getCompoundDrawables()[2];
//如果右侧没有图标,则不做处理
if (drawableRight == null){
return false;
}else if (motionEvent.getAction() != MotionEvent.ACTION_UP){
//如果不是按下事件,不做处理
return false;
}else if (motionEvent.getX() > editText.getWidth()-editText.getPaddingEnd()-drawableRight.getIntrinsicWidth()){
//如果点击的位置在右侧图标处,则清空输入框
editText.setText("");
}
return false;
}
}
上面的代码实现了需求4,针对需求1,2可以通过监听EditText的输入来实现。在此之前,有一个地方需要注意,就是通过代码设置EditText的右侧图标:
editText.setCompoundDrawablesRelativeWithIntrinsicBounds(null, null, context.getDrawable(R.drawable.ic_cancel), null);
或者
editText.setCompoundDrawablesWithIntrinsicBounds(null, null, context.getDrawable(R.drawable.ic_cancel), null);
其他几个方法似乎无法设置图标:
editText.setCompoundDrawables(Drawable left, Drawable top, Drawable right, Drawable bottom);
editText.setCompoundDrawablesRelative(Drawable start, Drawable top, Drawable end, Drawable bottom);
具体原因暂时没有深入探究。
EditText输入监听
public class InputClearOnTextChangedListener implements TextWatcher {
private Context context;
private EditText editText;
public InputClearOnTextChangedListener(Context context, EditText editText){
this.context = context;
this.editText = editText;
}
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void afterTextChanged(Editable editable) {
//当输入框有字符输入时,显示清除图标,没有字符时隐藏清除图标
if (editable.length()>0){
editText.setCompoundDrawablesRelativeWithIntrinsicBounds(null, null, context.getDrawable(R.drawable.ic_cancel), null);
//editText.setCompoundDrawablesWithIntrinsicBounds(null, null, context.getDrawable(R.drawable.ic_cancel), null);
}else {
editText.setCompoundDrawablesRelativeWithIntrinsicBounds(null, null, null, null);
//editText.setCompoundDrawablesWithIntrinsicBounds(null, null, null, null);
}
}
}
对于需求3,可以监听EditText的焦点来实现
EditText焦点监听
public class InputClearOnFocusChangeListener implements View.OnFocusChangeListener {
private Context context;
private EditText editText;
public InputClearOnFocusChangeListener(Context context, EditText editText){
this.context = context;
this.editText = editText;
}
@Override
public void onFocusChange(View view, boolean hasFocus) {
//失去焦点时隐藏图标,取得焦点且输入框中有字符时,显示图标
if (hasFocus && editText.getText().length()>0){
editText.setCompoundDrawablesRelativeWithIntrinsicBounds(null, null, context.getDrawable(R.drawable.ic_cancel), null);
}else {
editText.setCompoundDrawablesRelativeWithIntrinsicBounds(null, null, null, null);
}
}
}
在Activity中对相应的EditText绑定监听器
//当输入框有字符输入时,显示清除图标,没有字符时隐藏清除图标
usernameInput.addTextChangedListener(new InputClearOnTextChangedListener(this, usernameInput));
//根据点击位置设置清除图标的功能(drawableRight没有点击事件)
usernameInput.setOnTouchListener(new InputClearOnTouchListener(usernameInput));
//失去焦点时隐藏图标,取得焦点且输入框中有字符时,显示图标
usernameInput.setOnFocusChangeListener(new InputClearOnFocusChangeListener(this, usernameInput));
passInput.addTextChangedListener(new InputClearOnTextChangedListener(this, passInput));
passInput.setOnTouchListener(new InputClearOnTouchListener(passInput));
passInput.setOnFocusChangeListener(new InputClearOnFocusChangeListener(this, passInput));
实现效果

代码改进
将三个监听器的代码写在一个类里,并且提供一个静态方法绑定监听器,减少代码量
public class InputClearListener implements View.OnTouchListener, TextWatcher, View.OnFocusChangeListener {
private Context context;
private EditText editText;
public InputClearListener(Context context, EditText editText){
this.context = context;
this.editText = editText;
}
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
//获取右侧图标
Drawable drawableRight = editText.getCompoundDrawables()[2];
//如果右侧没有图标,则不做处理
if (drawableRight == null){
return false;
}else if (motionEvent.getAction() != MotionEvent.ACTION_UP){
//如果不是按下事件,不做处理
return false;
}else if (motionEvent.getX() > editText.getWidth()-editText.getPaddingEnd()-drawableRight.getIntrinsicWidth()){
//如果点击的位置在右侧图标处,则清空输入框
editText.setText("");
}
return false;
}
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void afterTextChanged(Editable editable) {
//当输入框有字符输入时,显示清除图标,没有字符时隐藏清除图标
if (editable.length()>0){
editText.setCompoundDrawablesRelativeWithIntrinsicBounds(null, null, context.getDrawable(R.drawable.ic_cancel), null);
//editText.setCompoundDrawablesWithIntrinsicBounds(null, null, context.getDrawable(R.drawable.ic_cancel), null);
}else {
editText.setCompoundDrawablesRelativeWithIntrinsicBounds(null, null, null, null);
//editText.setCompoundDrawablesWithIntrinsicBounds(null, null, null, null);
}
}
@Override
public void onFocusChange(View view, boolean hasFocus) {
//失去焦点时隐藏图标,取得焦点且输入框中有字符时,显示图标
if (hasFocus && editText.getText().length()>0){
editText.setCompoundDrawablesRelativeWithIntrinsicBounds(null, null, context.getDrawable(R.drawable.ic_cancel), null);
}else {
editText.setCompoundDrawablesRelativeWithIntrinsicBounds(null, null, null, null);
}
}
/**
* 给EditText对象绑定监听器
* @param context EditText所在的activity
* @param editText 需要绑定监听器的EditText
*/
public static void addListener(Context context, EditText editText){
InputClearListener listener = new InputClearListener(context, editText);
editText.addTextChangedListener(listener);
editText.setOnTouchListener(listener);
editText.setOnFocusChangeListener(listener);
}
}
修改Activity中绑定监听器的代码
InputClearListener.addListener(this, usernameInput);
InputClearListener.addListener(this, passInput);
代码看起来比以前的简洁了不少。