前两天项目中需要用到带清除按钮的输入框,Android的控件就是不好,都不自带的,看iOS的多好,自带光环......哈哈
不吹牛了,本来是打算找一个的,但是一想也不是很难就自己撸一个。
下面是github地址,欢迎点赞支持哦:
github地址:https://github.com/MZCretin/ClearEditTextProject
效果:

我用了三种方式实现了一下这个功能。
第一种:
直接用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,当内容不为空的时候,重绘删除按钮。
这种实现的方式好在不会占用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.0'
}
最后如果您觉得有帮助,请打赏我一杯咖啡的钱!谢谢

网友评论