如何自定义一个带删除功能的EditText

其实早就想写一篇关于自定义控件的文章,可是总感觉没有什么可以下笔的,自定义控件其实并不麻烦,但是总想不出什么实用性比较强的控件。(其实是太难的我也不会,哈哈,不过不要在意这些细节)首先我们要知道,自定义控件分三种类型:1,继承已有的view,然后去重写 2,直接继承view,自己去draw 3,组合控件。今天我要讲的是如何自定义一个删除功能的EditText,很明显属于第一种类型,因为我要继承系统的EditText去实现。

那么我先说一下我的需求:

1)自定义的EditText可以实现清空输入内容的功能,即删除功能

2)删除的图标在输入框内容不为空,并且焦点在当前EditText上时才会显示

效果如下图:


自定义EditText代码如下:

package com.personal.xiaoshuai.customedittextdemo;

import android.content.Context;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;
import android.widget.EditText;

public class EditTextWithClear extends EditText {
    private String TAG = EditTextWithClear.class.getSimpleName();
    private Drawable dRight;
    private Rect rBounds;
    private Context context;
    private int offset;
    private boolean isEmpty = true;//输入是否为空,默认为true

    public EditTextWithClear(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        this.context = context;
        bindListener();
    }

    public EditTextWithClear(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.context = context;
        bindListener();
    }

    public EditTextWithClear(Context context) {
        super(context);
        this.context = context;
        bindListener();
    }

    private void bindListener() {
        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) {
                Log.i(TAG, "-----afterTextChanged-----");
                isEmpty = TextUtils.isEmpty(s) ? true : false;
                //输入框内容不为空,并且有焦点
                if (!isEmpty && hasFocus()) {
		    //这可以根据自己的需求替换成自己喜欢的删除图片
                    Drawable drawable = context.getResources().getDrawable(R.drawable.backspace);
		    //这行代码是必须的  否则图片会不显示
                    drawable.setBounds(0, 0, drawable.getMinimumWidth(), drawable.getMinimumHeight());
                    setClearDrawable(drawable);
                } else {
                    setClearDrawable(null);
                }

            }
        });
        setOnFocusChangeListener(new OnFocusChangeListener() {
            @Override
            public void onFocusChange(View v, boolean hasFocus) {
                Log.i(TAG, "-----onFocusChange-----");
                Log.i(TAG, "hasFocus:" + hasFocus());
                //输入框内容不为空,并且有焦点
                if (!isEmpty && hasFocus) {
                    Drawable drawable = context.getResources().getDrawable(R.drawable.backspace);
                    drawable.setBounds(0, 0, drawable.getMinimumWidth(), drawable.getMinimumHeight());
                    setClearDrawable(drawable);
                } else {
                    setClearDrawable(null);
                }
            }
        });
    }

    /**
     * 这个方法是配合padding来用的,是根据我自己的实际需求添加的, 大家可以不用关心offset有什么用
     *
     * @param right
     * @param offset
     */
    public void setClearDrawable(Drawable right, int offset) {
        this.offset = offset;
        setCompoundDrawables(getCompoundDrawables()[0], getCompoundDrawables()[1], right, getCompoundDrawables()[3]);
    }

    /**
     * @param right
     */
    public void setClearDrawable(Drawable right) {
        setCompoundDrawables(getCompoundDrawables()[0], getCompoundDrawables()[1], right, getCompoundDrawables()[3]);
    }

    @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();
            //判断点击区域是否在删除按钮的区域内
            if (x >= (this.getRight() - offset - rBounds.width() - dp2px(context, 15) * 2)
                    && x <= (this.getRight() - this.getPaddingRight())
                    && y >= this.getPaddingTop()
                    && y <= (this.getHeight() - this.getPaddingBottom())
                    && getCompoundDrawables()[2] != null
                    ) {
                this.setText("");
                //阻止键盘弹出
                event.setAction(MotionEvent.ACTION_CANCEL);
            }
        }
        return super.onTouchEvent(event);
    }

    @Override
    protected void finalize() throws Throwable {
        dRight = null;
        rBounds = null;
        super.finalize();
    }

    /**
     * dp转px
     *
     * @param context
     * @return
     */
    public int dp2px(Context context, float dpVal) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
                dpVal, context.getResources().getDisplayMetrics());
    }

}
使用就和一般的控件一样,直接用就可以,下面我贴一下我demo的代码
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.personal.xiaoshuai.customedittextdemo.MainActivity"
    >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:padding="15dp"
        android:orientation="vertical">
        <com.personal.xiaoshuai.customedittextdemo.EditTextWithClear
            android:id="@+id/et_user"
            android:layout_width="match_parent"
            android:layout_height="45dp"
            android:drawableLeft="@drawable/selector_et_user"
            android:drawablePadding="5dp"
            android:hint="用户名"
            />

        <com.personal.xiaoshuai.customedittextdemo.EditTextWithClear
            android:id="@+id/et_password"
            android:layout_width="match_parent"
            android:layout_height="45dp"
            android:layout_marginTop="25dp"
            android:drawablePadding="5dp"
            android:drawableLeft="@drawable/selector_et_password"
            android:inputType="textPassword"
            android:hint="密  码"
            />
    </LinearLayout>



</RelativeLayout>

selector_et_user.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_focused="true" android:drawable="@drawable/user_focus"/>
    <item android:state_focused="false" android:drawable="@drawable/user_nomal"/>
</selector>
selector_et_password.xml类似我就不贴了,Activity中没有逻辑代码,也不贴了。今天就写到这吧,其实写这篇文章成就感不是很强,因为自定义控件的精华所在(自定义控件属性)并没有涉及到,而且在调试过程中遇到点小问题,宝宝心里苦,但是宝宝不说~ 这个算是我的失眠之作了 ( ̄o ̄) . z Z




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值