自定義EditText :下劃線,左側有可變圖標,右側有可變刪除標誌

項目要求:1做出包含根據情況可變色的下劃線,左側有可變圖標,右側有可變刪除標誌的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://www.oschina.net/question/54100_32466
http://www.oschina.net/android/125/attrs-xml
http://blog.csdn.net/llew2011/article/details/28909193
http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2013/0307/986.html


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章