Android自定义具有清除输入的EditText

最近在做毕设,参照美团UI的时候,发现美团的输入框在输入的时候在右面会出现一个小叉,点击之后可以清除输入的内容:
这里写图片描述

花点时间实现一下

实现目标:在没有输入内容的时候,清除图标是隐藏的,当输入内容时,清除图标出现,点击可以清除输入的内容,清除之后隐藏清除图标。
  • 创建一个类EditTextWithDelete,继承EditText
public class EditTextWithDelete extends EditText {

}

这个时候编译器会提醒你
there is no default constructor available in ‘android.weight.EditText’

这个一般是父类没有无参构造函数,我们可以去看一下EditText的代码,看一下它的构造函数

    public EditText(Context context) {
        this(context, null);
    }

    public EditText(Context context, AttributeSet attrs) {
        this(context, attrs, com.android.internal.R.attr.editTextStyle);
    }

    public EditText(Context context, AttributeSet attrs, int defStyleAttr) {
        this(context, attrs, defStyleAttr, 0);
    }

    public EditText(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

EditText类的确是没有无参构造函数,那么我们给我们的EditTextWithDelete添加这四个构造函数

    public EditTextWithDelete(Context context) {
        this(context, null);
    }

    public EditTextWithDelete(Context context, AttributeSet attrs) {
        this(context, attrs, com.android.internal.R.attr.editTextStyle);
    }

    public EditTextWithDelete(Context context, AttributeSet attrs, int defStyleAttr) {
        this(context, attrs, defStyleAttr, 0);
    }

    public EditTextWithDelete(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }
  • 获得我们删除图标的对象并在创建自定义EditText的时候初始化

我们在创建这个View的时候,需要在EditText的基础上在EditText的右面添加一个删除图片,所以每个构造方法中我们都需要得到这个对象,并且通过判断条件,来设置初始状态,那么我们写一个初始化函数

private Drawable delete;

private void init(){
          delete = getContext().getResources().getDrawable(R.drawable.search_box_delete);
          //如果没有输入内容,让图片不可见
          if(length() == 0){
               //图片不可见逻辑
          }
          //如果输入内容,让图片可见
          else{
               //图片可见逻辑
          }
}

然后在每个构造函数中调用一下这个初始化函数即可

  • 设置文本变化监听,来控制删除图标的出现与消失

这个监听也需要放在初始化函数中,保证每个构造函数都有,而且我们只需要添加文本变化后的监听逻辑,那么我们更改一下初始化函数

private void init(){
        delete = getContext().getResources().getDrawable(R.drawable.search_box_delete);
        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) {

            }
            //文本变化后
            @Override
            public void afterTextChanged(Editable s) {
                //如果还没输入内容,让图片不可见
               if(length() == 0){
                    //图片不可见逻辑
                }
                //如果输入内容,让图片可见
                else{
                    //图片可见逻辑
                }
            }
        });

           if(length() == 0){
              //图片不可见逻辑
           }
           //如果输入内容,让图片可见
           else{
               //图片可见逻辑
           }
    }

这个图片设置的逻辑重复,提取成一个函数,如下:

private void setDeletePicture() {
        //文本框没有内容,则图片不出现
        if (length() == 0) {
            //图片不可见逻辑
        }
        //文本框有输入内容时,图片出现
        else {
            //图片可见逻辑
        }
    }

然后在init()函数中调用setDeletePicture控制图片的可见不可见

  • 接下来就是图片可见于不可见的方法

一开始我最先想到的是setVisibility,后来才想到我们这是一张图片,不是一个ImageView,睡一觉,清醒清醒…. 既然是图片,又想到设置透明度,还是不可以,没有任何效果,然后点进EditText这个类里面看了一下,发现一个setCompoundDrawables函数,他的参数里有drawable对象,度娘了一把,发现一个介绍setCompoundDrawables与setCompoundDrawablesWithIntrinsicBounds区别的博客,然后在EditText的代码里果然找到了第二个函数…..

在这里顺便记一下它们两个的区别(复制自):

手工设置文本与图片相对位置时,常用到如下方法:

setCompoundDrawables(left, top, right, bottom)


setCompoundDrawablesWithIntrinsicBounds(left, top, right, bottom)


意思是设置Drawable显示在text的左、上、右、下位置。


但是两者有些区别:
setCompoundDrawables 画的drawable的宽高是按drawable.setBound()设置的宽高,
所以才有The Drawables must already have had setBounds(Rect) called.

使用之前必须使用Drawable.setBounds设置Drawable的长宽。


setCompoundDrawablesWithIntrinsicBounds是画的drawable的宽高是按drawable固定的宽高,
所以才有The Drawables' bounds will be set to their intrinsic bounds.

intrinsic bounds.

即通过getIntrinsicWidth()与getIntrinsicHeight获得

根据上面博客的介绍,那我们的图片可见不可见逻辑就好写多了,而且还能设置图片基于EditText的位置,我们的目标任务是让删除内容的图片出现在EditText的最右面,setCompoundDrawablesWithIntrinsicBounds(left, top, right, bottom),第三个参数是设置为右面,那么我们修改setDeletePicture函数

private void setDeletePicture() {
        //文本框没有内容,则图片不出现
        if (length() == 0) {
            setCompoundDrawablesWithIntrinsicBounds(null, null, null, null);
        }
        //文本框有输入内容时,图片出现,并且出现在右面
        else {
            setCompoundDrawablesWithIntrinsicBounds(null, null, delete, null);
       }
 }

图片的可见不可见逻辑完毕,接下来是我们点击删除的图片可以清空我们的文本框,那么思路也很简单:用户点击图片区域,设置setText(“”)即可

  • 点击图片,清空输入框内容

我们用的是一张图片,那么我们现在的主要目标是获取用户点击的位置,然后判断这个位置是不是处于我们图片的区域

在这里,图片一般不是很大,为了用户操作的方便,我们判断的内容更改为图片左边到图片右边的整个EidtText的区域为点击效果区域(用户点击该区域内的点即为点击图片),如下图
这里写图片描述

假如红色区域为图片内容区域,那么点击效果区域为黑色所围的区域

那么我们需要得到图片的左边的位置以及右边的位置。

右边的位置很容易得到,创建一个矩形,通过getGlobalVisibleRect(rect)方法,将它的大小调整为EditText的大小,这时它的右边与图片的右边是一致的(在EditText创建矩形相当于创建一个和EditText一样的矩形,那么矩形的右边就是EditText的右边,也是图片的右边,因为图片我们设置在EditText的右边)

那么左边的位置就是:矩形的右边位置-图片的宽度
这里左边的位置也可以根据自己需要调整,比如说你可以不减去图片的宽度,减去的值越大,点击效果区域越大

OK,位置都得到了,我们调整矩形的左边,将其设为我们刚才得到的左边位置,矩形大小即便为了上面图片的黑框所包围的区域

那么判断是否清楚内容时只需要判断用户点击的位置是否处于矩形范围内即可

public boolean onTouchEvent(MotionEvent event) {

        if (delete != null && event.getAction() == MotionEvent.ACTION_UP) {
            //获取用户点击的位置
            int eventX = (int) event.getRawX();
            int eventY = (int) event.getRawY();

            //创建一个矩形
            Rect rect = new Rect();
            //返回一个EditText大小的矩形
            getGlobalVisibleRect(rect);
            //更改矩形的左边界
            rect.left = rect.right - delete.getIntrinsicWidth();
            //判断用户点击位置是否在矩形范围内,是,则清空输入内容
            if (rect.contains(eventX, eventY))
                setText("");
        }
        return super.onTouchEvent(event);
    }

最后,完整代码如下:

public class EditTextWithDelete extends EditText {
    private Drawable delete;
    //父类没有无参构造函数
    public EditTextWithDelete(Context context) {
        this(context, null);
        init();
    }

    public EditTextWithDelete(Context context, AttributeSet attrs) {
        this(context, attrs,editTextStyle);
        init();
    }

    public EditTextWithDelete(Context context, AttributeSet attrs, int defStyleAttr) {
        this(context, attrs, defStyleAttr, 0);
        init();
    }
    public EditTextWithDelete(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init();
    }




    private void init(){
        delete = getContext().getResources().getDrawable(R.drawable.search_box_delete);
        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) {

            }

            @Override
            public void afterTextChanged(Editable s) {
                setDrawable();
            }
        });
        setDrawable();
    }
    private void setDrawable() {
        //文本框没有内容,则图片不出现
        if (length() == 0) {
            setCompoundDrawablesWithIntrinsicBounds(null, null, null, null);
        }
        //文本框有输入内容时,文本框出现
        else {
            setCompoundDrawablesWithIntrinsicBounds(null, null, delete, null);
        }
    }
    public boolean onTouchEvent(MotionEvent event) {
        if (delete != null && event.getAction() == MotionEvent.ACTION_UP) {
            //获取用户点击的位置
            int eventX = (int) event.getRawX();
            int eventY = (int) event.getRawY();
            //创建一个矩形
            Rect rect = new Rect();
            //返回一个EditText大小的矩形
            getGlobalVisibleRect(rect);
            //更改矩形的左边界
            rect.left = rect.right - delete.getIntrinsicWidth();
            //判断用户点击位置是否在矩形范围内,是,则清空输入内容
            if (rect.contains(eventX, eventY))
                setText("");
        }
        return super.onTouchEvent(event);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值