項目要求: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();
}
}
效果圖:
代碼解釋:
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