大部分的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); } }