大部分的android应用中的文本框都带有清除按钮,在输入长文本后可以一次清除所有输入,实现的思路有很多,比如直接用EditText+ImageView,但是每个文本框都要这么搞麻烦不说,且不利于维护。
本文的实现思路是通过继承EditText,并通过复写draw方法,将清除按钮画出来,然后通过监听onTouchEvent方法,判定用户是否点击了draw出来的区域进而判定是否需要清除文本。
以下是两种方式区别不大,方法一使用了资源图片作为清除按钮,方法二使用了android的绘图api绘制清除按钮。
方法一:
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.EditText;
public class MyEditText extends EditText implements TextWatcher {
private float density;
private boolean drawableShown = false;
private Drawable drawable;
private int drawableWidth;
private int drawableHeight;
private int paddingLeft;
private int paddingTop;
private int paddingRight;
private int paddingBottom;
public MyEditText(Context context, AttributeSet attrs) {
super(context, attrs);
// 密度
density = context.getResources().getDisplayMetrics().density;
// 删除图标
drawable = getResources().getDrawable(R.drawable.sdk_cancel);
drawableWidth = drawable.getIntrinsicWidth();
drawableHeight = drawable.getIntrinsicHeight();
paddingLeft = getPaddingLeft();
paddingTop = getPaddingTop();
paddingRight = getPaddingRight();
paddingBottom = getPaddingBottom();
setPadding(paddingLeft, paddingTop, paddingRight + drawableWidth, paddingBottom);
addTextChangedListener(this);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
if (drawable.getBounds().contains((int)event.getX(), (int)event.getY())) {
return true;
}
break;
case MotionEvent.ACTION_UP:
if (drawable.getBounds().contains((int)event.getX(), (int)event.getY())) {
// 删除文本
setText("");
// 重新请求布局
requestLayout();
return true;
}
break;
}
return super.onTouchEvent(event);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
if (!TextUtils.isEmpty(getText())) {
int width = drawableWidth; // 图标宽
int height = drawableHeight; // 图标高
int w = right - left; // 控件宽
int h = bottom - top; // 控件高
width = Math.min(width, w);
height = Math.min(height, h);
width = height = Math.min(width, height);
// 设置图标已显示
drawableShown = true;
int l = w - width;
l = l <= 0 ? 0 : l - (w - l - getDp(getPaddingLeft() + getPaddingRight())) / 2;
int t = (h-height)/2;
int r = l + width;
int b = t + height;
drawable.setBounds(l, t, r, b);
} else {
// 设置图标已隐藏
drawableShown = false;
drawable.setBounds(0, 0, 0, 0);
}
}
@Override
public void draw(Canvas canvas) {
super.draw(canvas);
// 将图标绘制到界面
drawable.draw(canvas);
}
@Override
public void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) {
super.onTextChanged(text, start, lengthBefore, lengthAfter);
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void afterTextChanged(Editable s) {
// 当有文本没有显示删除图标时和没有文本显示删除图标时,重新请求布局
if ((!drawableShown && !TextUtils.isEmpty(s)) || (drawableShown && TextUtils.isEmpty(s))) {
requestLayout();
}
}
private int getPx(int dp) {
return (int)(dp * density + 0.5f);
}
private int getDp(int px) {
return (int)(px / density + 0.5f);
}
}
方法二:
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.EditText;
public class MyEditText1 extends EditText {
private Paint circlePaint;
private Paint plusPaint;
private Paint clearPaint;
private Rect clearRect;
private Rect clearRectPx;
private int circleRadiusDp;
private int circleRadius;
private int circlePaddingDp;
private int circlePadding;
private int clearRectBox;
public MyEditText1(Context context, AttributeSet attrs) {
super(context, attrs);
circlePaint = new Paint();
circlePaint.setColor(Color.GRAY);
plusPaint = new Paint();
plusPaint.setColor(Color.WHITE);
plusPaint.setStrokeWidth(getPx(5));
clearPaint = new Paint();
clearPaint.setColor(Color.argb(0, 0, 0, 0));
clearRect = new Rect();
clearRectPx = new Rect();
circleRadiusDp = 10;
circleRadius = getPx(circleRadiusDp);
circlePaddingDp = 3;
circlePadding = getPx(circlePaddingDp);
clearRectBox = circleRadiusDp * 2 + circlePaddingDp * 2;
//
if (0 == getPaddingRight() || getPaddingRight() < getPx(clearRectBox)) {
setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight() + getPx(clearRectBox), getPaddingBottom());
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (MotionEvent.ACTION_DOWN == event.getAction()) {
if (clearRect.contains((int)event.getX(), (int)event.getY())) {
return true;
}
} else if (MotionEvent.ACTION_UP == event.getAction()) {
if (!TextUtils.isEmpty(getText()) && clearRect.contains((int)event.getX(), (int)event.getY())) {
setText("");
return true;
}
}
return super.onTouchEvent(event);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
int l = right - left - clearRectBox*2 - getDp(getPaddingLeft() - getDp(getPaddingRight()));
int t = (bottom - top - clearRectBox - getDp(getPaddingTop()) - getDp(getPaddingBottom())) / 2 + getDp(getPaddingTop());
int r = l + clearRectBox;
int b = t + clearRectBox;
clearRect.set(l-clearRectBox, t-clearRectBox, r+clearRectBox, b+clearRectBox);
clearRectPx.set(l, t, r, b);
}
@Override
public void draw(Canvas canvas) {
super.draw(canvas);
if (!TextUtils.isEmpty(getText())) {
canvas.drawRect(clearRect, clearPaint);
canvas.translate(clearRectPx.centerX(), clearRectPx.centerY());
canvas.save();
canvas.drawCircle(0, 0, circleRadius, circlePaint);
canvas.restore();
canvas.save();
canvas.rotate(45);
canvas.translate(-(circleRadius - circlePadding), 0);
canvas.drawLine(0, 0, circleRadius*2 - circlePadding*2, 0, plusPaint);
canvas.restore();
canvas.save();
canvas.rotate(135);
canvas.translate(-(circleRadius - circlePadding), 0);
canvas.drawLine(0, 0, circleRadius*2 - circlePadding*2, 0, plusPaint);
canvas.restore();
}
}
private int getPx(int dp) {
return (int)(dp * getContext().getResources().getDisplayMetrics().density + 0.5f);
}
private int getDp(int px) {
return (int)(px / getContext().getResources().getDisplayMetrics().density + 0.5f);
}
}