软件编程
位置:首页>> 软件编程>> Android编程>> Android如何自定义EditText下划线?

Android如何自定义EditText下划线?

作者:OneAPM  发布时间:2022-06-27 10:49:07 

标签:Android,EditText,下划线

曾经做过一个项目,其中登录界面的交互令人印象深刻。交互设计师给出了一个非常作的设计,要求做出包含根据情况可变色的下划线,左侧有可变图标,右侧有可变删除标志的输入框,如图

Android如何自定义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();
}
}

效果图:

Android如何自定义EditText下划线?

代码解释:

变量名 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=""

1、onTouchEvent 当手机点击时,第一个先执行的函数,当点击右侧删除图标是清空 edittext
2、setStatus 根据不同的状态,左边的图片不一样

存在的问题: 这版本虽然基本功能已经实现,但是不符合需求,设计中要求文本框中无文字时,右侧删除按钮不显示,不点击删除按钮,删除按钮要保持灰色,点击时才可以变蓝色。

因此有了第二个版本


public class LineEditText extends EditText implements TextWatcher, <br /> 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

当进入界面,点击输入框,要判断输入框中是否已有文字,如果有则显示灰色的删除按钮,如果没有则不显示,如果点击了删除按钮,删除按钮变蓝色

存在的问题: 这个版本依旧存在问题,就是输入长度超过输入框,所画的线不会延伸,如图

Android如何自定义EditText下划线?

解决方法:


@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:延伸后的长度

最终效果:

Android如何自定义EditText下划线?

0
投稿

猜你喜欢

手机版 软件编程 asp之家 www.aspxhome.com