Android开发之——三种方式来自定义一个带清除(Clear)按钮的EditText

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u010998327/article/details/77104711

Android开发之——三种方式来自定义一个带清除(Clear)按钮的EditText


前两天项目中需要用到带清除按钮的输入框,Android的控件就是不好,都不自带的,看iOS的多好,自带光环……哈哈

不吹牛了,本来是打算找一个的,但是一想也不是很难就自己撸一个。

下面是github地址,欢迎点赞支持哦:

github地址https://github.com/MZCretin/ClearEditTextProject


效果:

ezgif.com-video-to-gif.gif


我用了三种方式实现了一下这个功能。

第一种:

直接用ViewGroup包住两个控件,一个EditText,一个ImageView,用代码布局好,然后去监听EditText的输入状态,当EditText内容不为空的时候显示ImageView,在EditText内容为空的时候隐藏ImageView,然后给ImageView添加监听事件,然后清空EditText,这是最简单想到的。下面贴出代码。

这种实现方式,需要分别获取到EditText和ImageView然后分别用java代码对两者的属性进行设置,修改展示的样式不是很方便。

package com.cretin.www.clearedittextproject.view;

import android.content.Context;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.cretin.www.clearedittextproject.R;

/**
 * Created by Cretin on 2017/8/8.
 */

public class ClearEditText extends LinearLayout {
    private EditText mEdittext;
    private ImageView mImageView;
    private Context mContext;
    private float scaleSize;

    public ClearEditText(Context context) {
        super(context);
        init(context);
    }

    public ClearEditText(Context context, AttributeSet attrs) {
        super(context,attrs);
        init(context);
    }

    public ClearEditText(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }

    private void init(Context context) {
        mContext = context;
        //设置方向
        setOrientation(HORIZONTAL);
        //获取当前设备的屏幕密度(自创)
        scaleSize = getScale(context);

        mEdittext = new EditText(mContext);
        //充满布局展示
        LayoutParams layoutParams = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.MATCH_PARENT);
        //设置权重
        layoutParams.weight = 1;
        //设置内边距  如果要投入使用最好不要写死,需要后续封装,通过自定义属性设置
        mEdittext.setPadding(( int ) (10 * scaleSize), ( int ) (4 * scaleSize),
                ( int ) (10 * scaleSize), ( int ) (4 * scaleSize));
        //添加到布局中去
        addView(mEdittext, layoutParams);

        mImageView = new ImageView(mContext);
        //设置资源文件  如果要投入使用最好不要写死,需要后续封装,通过自定义属性设置
        mImageView.setImageResource(R.mipmap.clear);
        //设置ImageView的大小
        LayoutParams layoutParamsImage = new
                LayoutParams(( int ) (30 * scaleSize), ( int ) (30 * scaleSize));
        //设置内边距  如果要投入使用最好不要写死,需要后续封装,通过自定义属性设置
        mImageView.setPadding(5, 5, 5, 5);
        //设置不可见
        mImageView.setVisibility(INVISIBLE);
        //添加到布局中去
        addView(mImageView, layoutParamsImage);
        setGravity(Gravity.CENTER);

        //设置事件监听
        mImageView.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View view) {
                mEdittext.getEditableText().clear();
            }
        });

        //添加内容变化监听
        mEdittext.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
            }

            @Override
            public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
                //内容不为空的时候显示清除按钮
                if ( !TextUtils.isEmpty(charSequence) ) {
                    mImageView.setVisibility(VISIBLE);
                } else {
                    mImageView.setVisibility(INVISIBLE);
                }
            }

            @Override
            public void afterTextChanged(Editable editable) {

            }
        });
    }

    public EditText getmEdittext() {
        return mEdittext;
    }

    public ImageView getmImageView() {
        return mImageView;
    }

    /**
     * 获取屏幕缩放比
     *
     * @param context
     * @return
     */
    private float getScale(Context context) {
        TextView tv = new TextView(context);
        tv.setTextSize(1);
        return tv.getTextSize();
    }
}

第二种:

自定义一个View继承自EditText,然后通过设置setCompoundDrawables(null, null, mClearDrawable, null);来设置右边的图片,然后通过监听onTouchEvent并且通过判断点击的位置判断是否点击到清除按钮来清除EditText的内容与否。

这种实现的方式比上一种实现的方式好的地方在于直接继承自EditText,拥有EditText的所有方法,比较方便修改自定义样式,但是还是又一个明显的缺点,因为内部是使用setCompoundDrawables(null, null, mClearDrawable, null)设置清除按钮的图片,所以使用者在自己使用setCompoundDrawables方法的时候会覆盖原有的逻辑,所以不能使用这个方法。

package com.cretin.www.clearedittextproject.view;

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

import com.cretin.www.clearedittextproject.R;

/**
 * Created by cretin on 2017/8/11.
 */

public class ClearEditText1 extends EditText {
    private Drawable mClearDrawable;
    private int mWidth;
    private int mHeight;

    public ClearEditText1(Context context) {
        super(context);
        init(context);
    }

    public ClearEditText1(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    public ClearEditText1(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }

    private void init(Context context) {
        //实例化右边的清除图片 如果要投入使用最好不要写死,需要后续封装,通过自定义属性设置
        mClearDrawable = context.getResources().getDrawable(R.mipmap.delete);

        addTextChangedListener(new TextWatcher() {
            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
            }

            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
            }

            @Override
            public void afterTextChanged(Editable s) {
                setDrawable();
            }
        });
    }

    //设置删除图片
    private void setDrawable() {
        if ( length() < 1 )
            setCompoundDrawablesWithIntrinsicBounds(null, null, null, null);
        else {
            mClearDrawable.setBounds(0, 0, mHeight / 2, mHeight / 2);
            setCompoundDrawables(null, null, mClearDrawable, null);
        }
    }

    // 处理删除事件
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if ( event.getAction() == MotionEvent.ACTION_UP ) {
            if ( event.getX() > getWidth()
                    - getPaddingRight()
                    - mClearDrawable.getIntrinsicWidth() ) {
                setText("");
            }
        }
        return super.onTouchEvent(event);
    }

    @Override
    protected void finalize() throws Throwable {
        super.finalize();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int desiredWidth = 100;
        int desiredHeight = 100;

        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);

        int width;
        int height;

        //Measure Width
        if ( widthMode == MeasureSpec.EXACTLY ) {
            //Must be this size
            width = widthSize;
        } else if ( widthMode == MeasureSpec.AT_MOST ) {
            //Can't be bigger than...
            width = Math.min(desiredWidth, widthSize);
        } else {
            //Be whatever you want
            width = desiredWidth;
        }

        //Measure Height
        if ( heightMode == MeasureSpec.EXACTLY ) {
            //Must be this size
            height = heightSize;
        } else if ( heightMode == MeasureSpec.AT_MOST ) {
            //Can't be bigger than...
            height = Math.min(desiredHeight, heightSize);
        } else {
            //Be whatever you want
            height = desiredHeight;
        }
        mWidth = width;
        mHeight = height;
        //MUST CALL THIS

//        如果要投入使用最好不要写死,需要后续封装,通过自定义属性设置
        setPadding(0, 0, mHeight / 4, 0);
        setDrawable();
        setMeasuredDimension(width, height);
    }
}

第三种:(也是推荐的)

自定义View继承自EditText,然后通过计算View的宽和高,确定右边的删除按钮的大小,在onDraw方法里面,我们会绘制一个删除按钮,按钮的大小由用户控制,我提供一个对外的接口,用于设置删除按钮的缩放大小,默认设置成0.5,也就是说按钮的大小是控件高度的一般,这样做的好处是方便适配所有情况。在安放好删除按钮之后,通过监听onTouchEvent方法监听按钮所在位置范围的点击事件的监听,检测到点击事件并且有文本框内容的时候,就清空文本框的内容。再监听addTextChangedListener,当内容不为空的时候,重绘删除按钮。

扫描二维码关注公众号,回复: 3054292 查看本文章

这种实现的方式好在不会占用EditText本身的方法,最大化放宽EditText的自定义范围。

package com.cretin.www.clearedittext.view;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.EditText;

import com.cretin.www.clearedittext.R;


/**
 * Created by cretin on 2017/8/11.
 */

public class ClearEditText extends EditText {
    private static final float DEFAUT_SCALE = 0.5f;
    private Bitmap mClearBitmap;
    private Paint mPaint;
    private int mWidth;
    private int mHeight;
    private boolean showClose;
    private float scale;
    private float padding;

    public ClearEditText(Context context) {
        super(context);
        init(context, null);
    }

    public ClearEditText(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs);
    }

    public ClearEditText(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context, attrs);
    }

    private void init(Context context, AttributeSet attrs) {
        int clearIcon = 0;
        if ( attrs != null ) {
            //获得这个控件对应的属性。
            TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.ClearEditText);
            try {
                //获得属性值
                clearIcon = a.getResourceId(R.styleable.ClearEditText_clearIcon, 0);
                scale = a.getResourceId(R.styleable.ClearEditText_scaleSize, 0);
            } finally { //回收这个对象
                a.recycle();
            }
        }
        //设置删除图标
        if ( clearIcon != 0 ) {
            mClearBitmap = BitmapFactory.decodeResource(getResources(), clearIcon);
        } else
            mClearBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.delete);

        if ( scale == 0 ) {
            scale = DEFAUT_SCALE;
        }

        mPaint = new Paint();

        addTextChangedListener(new TextWatcher() {
            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
                showClose = !TextUtils.isEmpty(s);
                invalidate();
            }

            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {

            }

            @Override
            public void afterTextChanged(Editable s) {
            }
        });
    }

    // 处理删除事件
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if ( event.getAction() == MotionEvent.ACTION_UP ) {
            //在图标的范围内点击有效
            if ( showClose && event.getX() > (getWidth() - getHeight() + padding)
                    && event.getX() < (getWidth() - padding)
                    && event.getY() > padding
                    && event.getY() < (getHeight() - padding) ) {
                setText("");
            }
        }
        return super.onTouchEvent(event);
    }

    @Override
    protected void finalize() throws Throwable {
        super.finalize();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        if ( showClose ) {
            Rect mSrcRect = new Rect(0, 0, mHeight, mHeight);
            RectF mDestRect = new RectF(mWidth - mHeight + padding,
                    padding, mWidth - padding, mHeight - padding);
            canvas.drawBitmap(mClearBitmap, mSrcRect, mDestRect, mPaint);
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int desiredWidth = 100;
        int desiredHeight = 100;

        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);

        int width;
        int height;

        //Measure Width
        if ( widthMode == MeasureSpec.EXACTLY ) {
            //Must be this size
            width = widthSize;
        } else if ( widthMode == MeasureSpec.AT_MOST ) {
            //Can't be bigger than...
            width = Math.min(desiredWidth, widthSize);
        } else {
            //Be whatever you want
            width = desiredWidth;
        }

        //Measure Height
        if ( heightMode == MeasureSpec.EXACTLY ) {
            //Must be this size
            height = heightSize;
        } else if ( heightMode == MeasureSpec.AT_MOST ) {
            //Can't be bigger than...
            height = Math.min(desiredHeight, heightSize);
        } else {
            //Be whatever you want
            height = desiredHeight;
        }
        mWidth = width;
        mHeight = height;
        //MUST CALL THIS

        //计算偏移量
        padding = (( float ) mHeight) * (1 - scale) / 2;
        setMeasuredDimension(width, height);
    }
}

代码比较简单,注释也比较清楚就不在赘述了。

推荐的是第三种方式,所以我打了个library上传上去了,至于其他两种方式,感兴趣的同学可以去github上clone源码下来试试水!

github地址https://github.com/MZCretin/ClearEditTextProject

提供一个简单集成方式:

Step 1. Add the JitPack repository to your build file

    allprojects {
        repositories {
            ...
            maven { url 'https://jitpack.io' }
        }
    }

Step 2. Add the dependency

  dependencies {
        compile 'com.github.MZCretin:ClearEditTextProject:1.3.0'
    }

最后如果您觉得有帮助,请打赏我一杯咖啡的钱!谢谢

4FBB6636F8B10048140091E3AF0AD974.png

猜你喜欢

转载自blog.csdn.net/u010998327/article/details/77104711