«

Android带清除按钮的文本框

时间:2024-3-2 19:07     作者:韩俊     分类: Android


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

}

标签: android

热门推荐