自定義EditText 實現帶清空按鈕的輸入框

ryan 8年前發布 | 14K 次閱讀 Android開發 移動開發

 注:本文轉載自csdn,其中實現清除功能所采用的方案比較可取。

原文如下:

項目要求:做出包含根據情況可變色的下劃線,左側有可變圖標,右側有可變刪除標志的edittext,如圖

記錄制作過程:

第一版本:

public class LineEditText extends EditText {
    private Paint mPaint;
    private int color;
    public static final int STATUS_FOCUSED = 1;
    public static final int STATUS_UNFOCUSED = 2;
    public static final int STATUS_ERROR = 3;
    private int status = 2;
    private Drawable del_btn;
    private Drawable del_btn_down;
    private int focusedDrawableId = R.drawable.user_select;// 默認的
    private int unfocusedDrawableId = R.drawable.user;
    private int errorDrawableId = R.drawable.user_error;
    Drawable left = null;
    private Context mContext;
    public LineEditText(Context context) {
        super(context);
        mContext = context;
        init();
    }
    public LineEditText(Context context, AttributeSet attrs) {
        super(context, attrs);
        mContext = context;
        init();
    }
    public LineEditText(Context context, AttributeSet attrs, int defStryle) {
        super(context, attrs, defStryle);
        mContext = context;
        TypedArray a = context.obtainStyledAttributes(attrs,
                R.styleable.lineEdittext, defStryle, 0);
        focusedDrawableId = a.getResourceId(
                R.styleable.lineEdittext_drawableFocus, R.drawable.user_select);
        unfocusedDrawableId = a.getResourceId(
                R.styleable.lineEdittext_drawableUnFocus, R.drawable.user);
        errorDrawableId = a.getResourceId(
                R.styleable.lineEdittext_drawableError, R.drawable.user_error);
        a.recycle();
        init();
    }
    /**
     * 2014/7/31
     *
     * @author Aimee.ZHANG
     */
    private void init() {
        mPaint = new Paint();
        // mPaint.setStyle(Paint.Style.FILL);
        mPaint.setStrokeWidth(3.0f);
        color = Color.parseColor("#bfbfbf");
        setStatus(status);
        del_btn = mContext.getResources().getDrawable(R.drawable.del_but_bg);
        del_btn_down = mContext.getResources().getDrawable(R.drawable.del_but_bg_down);
        addTextChangedListener(new TextWatcher() {
            @Override
            public void onTextChanged(CharSequence arg0, int arg1, int arg2,
                    int arg3) {
            }
            @Override
            public void beforeTextChanged(CharSequence arg0, int arg1,
                    int arg2, int arg3) {
            }
            @Override
            public void afterTextChanged(Editable arg0) {
                setDrawable();
            }
        });
        setDrawable();
    }
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        mPaint.setColor(color);
        canvas.drawLine(0, this.getHeight() - 1, this.getWidth(),
                this.getHeight() - 1, mPaint);
    }
    // 刪除圖片
    private void setDrawable() {
        if (length() < 1) {
            setCompoundDrawablesWithIntrinsicBounds(left, null, del_btn, null);
        } else {
            setCompoundDrawablesWithIntrinsicBounds(left, null, del_btn_down,null);
        }
    }
    // 處理刪除事件
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (del_btn_down != null && event.getAction() == MotionEvent.ACTION_UP) {
            int eventX = (int) event.getRawX();
            int eventY = (int) event.getRawY();
            Log.e("eventXY", "eventX = " + eventX + "; eventY = " + eventY);
            Rect rect = new Rect();
            getGlobalVisibleRect(rect);
            rect.left = rect.right - 50;
            if (rect.contains(eventX, eventY))
            setText("");
        }
        return super.onTouchEvent(event);
    }
    public void setStatus(int status) {
        this.status = status;

        if (status == STATUS_ERROR) {
            try {
                left = getResources().getDrawable(errorDrawableId);
            } catch (NotFoundException e) {
                e.printStackTrace();
            }
            setColor(Color.parseColor("#f57272"));
        } else if (status == STATUS_FOCUSED) {
            try {
                left = getResources().getDrawable(focusedDrawableId);
            } catch (NotFoundException e) {
                e.printStackTrace();
            }
            setColor(Color.parseColor("#5e99f3"));
        } else {
            try {
                left = getResources().getDrawable(unfocusedDrawableId);
            } catch (NotFoundException e) {
                e.printStackTrace();
            }
            setColor(Color.parseColor("#bfbfbf"));
        }
        if (left != null) {
//          left.setBounds(0, 0, 30, 40);
//          this.setCompoundDrawables(left, null, null, null);
            setCompoundDrawablesWithIntrinsicBounds(left,null,del_btn,null);
        }
        postInvalidate();
    }
    public void setLeftDrawable(int focusedDrawableId, int unfocusedDrawableId,
            int errorDrawableId) {
        this.focusedDrawableId = focusedDrawableId;
        this.unfocusedDrawableId = unfocusedDrawableId;
        this.errorDrawableId = errorDrawableId;
        setStatus(status);
    }
    @Override
    protected void onFocusChanged(boolean focused, int direction,
            Rect previouslyFocusedRect) {
        super.onFocusChanged(focused, direction, previouslyFocusedRect);
        if (focused) {
            setStatus(STATUS_FOCUSED);
        } else {
            setStatus(STATUS_UNFOCUSED);
        }
    }
    @Override
    protected void finalize() throws Throwable {
        super.finalize();
    };
    public void setColor(int color) {
        this.color = color;
        this.setTextColor(color);
        invalidate();
    }
}

效果圖:



代碼解釋:

變量名 STATUS_FOCUSED,STATUS_UNFOCUSED,STATUS_ERROR 標示了三種狀態,選中狀況為藍色,未選中狀態為灰色,錯誤狀態為紅色。focusedDrawableId   unfocusedDrawableId  errorDrawableId 存放三種狀態的圖片,放置于最左側。

canvas.drawLine(0, this.getHeight() - 1, this.getWidth(),this.getHeight() - 1, mPaint);    //畫editText最下方的線
setCompoundDrawablesWithIntrinsicBounds(left, null, del_btn, null);  //放置左邊的和右邊的圖片(左,上,右,下)
相當于 android:drawableLeft=""  android:drawableRight=""  

onTouchEvent  當手機點擊時,第一個先走的函數,當點擊右側刪除圖標是清空edittext

setStatus  更具不同的狀態,左邊的圖片不一樣


存在的問題:

這版本雖然基本功能已經實現,但是不符合需求,設計中要求文本框中無文字時,右側刪除按鈕不顯示,不點擊刪除按鈕,刪除按鈕要保持灰色,點擊時才可以變藍色。因此有了第二個版本

public class LineEditText extends EditText  implements TextWatcher,
OnFocusChangeListener{
    private Paint mPaint;
    private int color;
    public static final int STATUS_FOCUSED = 1;
    public static final int STATUS_UNFOCUSED = 2;
    public static final int STATUS_ERROR = 3;
    private int status = 2;
    private Drawable del_btn;
    private Drawable del_btn_down;
    private int focusedDrawableId = R.drawable.user_select;// 默認的
    private int unfocusedDrawableId = R.drawable.user;
    private int errorDrawableId = R.drawable.user_error;
    Drawable left = null;
    private Context mContext;
    /**
     * 是否獲取焦點,默認沒有焦點
     */
    private boolean hasFocus = false;
    /**
     * 手指抬起時的X坐標
     */
    private int xUp = 0;
    public LineEditText(Context context) {
        super(context);
        mContext = context;
        init();
    }
    public LineEditText(Context context, AttributeSet attrs) {
        super(context, attrs);
        mContext = context;
        init();
    }
    public LineEditText(Context context, AttributeSet attrs, int defStryle) {
        super(context, attrs, defStryle);
        mContext = context;
        TypedArray a = context.obtainStyledAttributes(attrs,
                R.styleable.lineEdittext, defStryle, 0);
        focusedDrawableId = a.getResourceId(
                R.styleable.lineEdittext_drawableFocus, R.drawable.user_select);
        unfocusedDrawableId = a.getResourceId(
                R.styleable.lineEdittext_drawableUnFocus, R.drawable.user);
        errorDrawableId = a.getResourceId(
                R.styleable.lineEdittext_drawableError, R.drawable.user_error);
        a.recycle();
        init();
    }
    /**
     * 2014/7/31
     *
     * @author Aimee.ZHANG
     */
    private void init() {
        mPaint = new Paint();
        // mPaint.setStyle(Paint.Style.FILL);
        mPaint.setStrokeWidth(3.0f);
        color = Color.parseColor("#bfbfbf");
        setStatus(status);
        del_btn = mContext.getResources().getDrawable(R.drawable.del_but_bg);
        del_btn_down = mContext.getResources().getDrawable(R.drawable.del_but_bg_down);
        addListeners();
        setCompoundDrawablesWithIntrinsicBounds(left, null, null, null);
    }
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        mPaint.setColor(color);
        canvas.drawLine(0, this.getHeight() - 1, this.getWidth(),
                this.getHeight() - 1, mPaint);
    }
    // 刪除圖片
//  private void setDrawable() {
//      if (length() < 1) {
//          setCompoundDrawablesWithIntrinsicBounds(left, null, null, null);
//      } else {
//          setCompoundDrawablesWithIntrinsicBounds(left, null, del_btn,null);
//      }
//  }
    // 處理刪除事件
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (del_btn != null && event.getAction() == MotionEvent.ACTION_UP) {
            // 獲取點擊時手指抬起的X坐標
            xUp = (int) event.getX();
            Log.e("xUp", xUp+"");
            /*Rect rect = new Rect();
            getGlobalVisibleRect(rect);
            rect.left = rect.right - 50;*/
              // 當點擊的坐標到當前輸入框右側的距離小于等于getCompoundPaddingRight()的距離時,則認為是點擊了刪除圖標
            if ((getWidth() - xUp) <= getCompoundPaddingRight()) {
                if (!TextUtils.isEmpty(getText().toString())) {
                    setText("");
                }
            }
        }else if(del_btn != null && event.getAction() == MotionEvent.ACTION_DOWN && getText().length()!=0){
            setCompoundDrawablesWithIntrinsicBounds(left,null,del_btn_down,null);
        }else if(getText().length()!=0){
            setCompoundDrawablesWithIntrinsicBounds(left,null,del_btn,null);
        }
        return super.onTouchEvent(event);
    }
    public void setStatus(int status) {
        this.status = status;

        if (status == STATUS_ERROR) {
            try {
                left = getResources().getDrawable(errorDrawableId);
            } catch (NotFoundException e) {
                e.printStackTrace();
            }
            setColor(Color.parseColor("#f57272"));
        } else if (status == STATUS_FOCUSED) {
            try {
                left = getResources().getDrawable(focusedDrawableId);
            } catch (NotFoundException e) {
                e.printStackTrace();
            }
            setColor(Color.parseColor("#5e99f3"));
        } else {
            try {
                left = getResources().getDrawable(unfocusedDrawableId);
            } catch (NotFoundException e) {
                e.printStackTrace();
            }
            setColor(Color.parseColor("#bfbfbf"));
        }
        if (left != null) {
//          left.setBounds(0, 0, 30, 40);
//          this.setCompoundDrawables(left, null, null, null);
            setCompoundDrawablesWithIntrinsicBounds(left,null,null,null);
        }
        postInvalidate();
    }
    public void setLeftDrawable(int focusedDrawableId, int unfocusedDrawableId,
            int errorDrawableId) {
        this.focusedDrawableId = focusedDrawableId;
        this.unfocusedDrawableId = unfocusedDrawableId;
        this.errorDrawableId = errorDrawableId;
        setStatus(status);
    }
     private void addListeners() {
            try {
                setOnFocusChangeListener(this);
                addTextChangedListener(this);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    @Override
    protected void onFocusChanged(boolean focused, int direction,
            Rect previouslyFocusedRect) {
        super.onFocusChanged(focused, direction, previouslyFocusedRect);
        this.hasFocus=focused;
        if (focused) {
            setStatus(STATUS_FOCUSED);
        } else {
            setStatus(STATUS_UNFOCUSED);
            setCompoundDrawablesWithIntrinsicBounds(left,null,null,null);
        }
    }
    @Override
    protected void finalize() throws Throwable {
        super.finalize();
    };
    public void setColor(int color) {
        this.color = color;
        this.setTextColor(color);
        invalidate();
    }

    @Override
    public void afterTextChanged(Editable arg0) {
        // TODO Auto-generated method stub
        postInvalidate();
    }
    @Override
    public void beforeTextChanged(CharSequence arg0, int arg1, int arg2,
            int arg3) {
        // TODO Auto-generated method stub
         if (TextUtils.isEmpty(arg0)) {
             // 如果為空,則不顯示刪除圖標
             setCompoundDrawablesWithIntrinsicBounds(left, null, null, null);
         } else {
             // 如果非空,則要顯示刪除圖標
             setCompoundDrawablesWithIntrinsicBounds(left, null, del_btn, null);
         }
    }
    @Override
     public void onTextChanged(CharSequence s, int start, int before, int after) {
       if (hasFocus) {
           if (TextUtils.isEmpty(s)) {
               // 如果為空,則不顯示刪除圖標
               setCompoundDrawablesWithIntrinsicBounds(left, null, null, null);
           } else {
               // 如果非空,則要顯示刪除圖標
               setCompoundDrawablesWithIntrinsicBounds(left, null, del_btn, null);
           }
       }
   }
    @Override
    public void onFocusChange(View arg0, boolean arg1) {
        // TODO Auto-generated method stub
        try {
            this.hasFocus = arg1;
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

效果圖:


比較關鍵的方法是:onTouchEvent

當進入界面,點擊輸入框,要判斷輸入框中是否已有文字,如果有則顯示灰色的刪除按鈕,如果沒有則不顯示,如果點擊了刪除按鈕,刪除按鈕變藍色

存在的問題:

這個版本依舊存在問題,就是輸入長度超過輸入框,所畫的線不會延伸,如圖


解決辦法:

@Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        mPaint.setColor(color);
        int x=this.getScrollX();
        int w=this.getMeasuredWidth();
        canvas.drawLine(0, this.getHeight() - 1, w+x,
                this.getHeight() - 1, mPaint);
    }

w:獲取控件長度

X:延伸后的長度

最終效果:


原文地址:http://blog.csdn.net/zwx622/article/details/38340991





 本文由用戶 ryan 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!