转载请注明出处
http://blog.youkuaiyun.com/shallcheek/article/details/51952625
1、概述
类似微信支付宝支付密码输入框,可以自定义密码长度,边框颜色,背景颜色,密码颜色等。
2、思路
当初想做这个的时候首先想的是自定义一个ViewGroup 里面add 一个EditView 通过这个EditView 的内容控制ViewGroup的背景绘制。
后面为了简单就直接自定义了一个EditView 通过自己的内容控制onDraw 绘制背景
3、步骤
初始化参数
private void init() {
//控制最大数量
if (password_max_len > 12) {
password_max_len = 12;
}
//初始化 Paint RectF
passwordPaint = new Paint();
passwordPaint.setAntiAlias(true);
passwordRoundPaint = new Paint();
passwordRoundPaint.setAntiAlias(true);
rectF = new RectF();
rectStrokeF = new RectF();
//隐藏光标
this.setCursorVisible(false);
//设置最大长度
this.setFilters(new InputFilter[]{new InputFilter.LengthFilter(password_max_len)});
//输入类型
setInputType(EditorInfo.TYPE_CLASS_NUMBER);
//输入框监听
addTextChangedListener(this);
//隐藏EditView 输入框的默认背景
setBackgroundColor(0x00000000);
}
初始化绘制相应参数,在设置EditView的属性
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
width = getWidth();
height = getHeight();
int min = Math.min(width / password_max_len, height);
if (passwordRadius > min / 2)
passwordRadius = min / 2;
rectF.top = 1;
rectF.left = 1;
rectF.right = width - 2;
rectF.bottom = height - 2;
rectStrokeF.top = 1;
rectStrokeF.left = 1;
rectStrokeF.right = width;
rectStrokeF.bottom = height;
}
onLayout
在这里初始化 rectF 和rectStrokeF 即 背景和背景边框的绘制参数
获取焦点
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
int action = event.getAction();
//触摸获取焦点弹出输入框
if (action == MotionEvent.ACTION_MOVE) {
//点击默认光标点再末尾
setSelection(getText().toString().length());
setFocusable(true);
setFocusableInTouchMode(true);
requestFocus();
InputMethodManager inputManager = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
inputManager.showSoftInput(this, 0);
}
//消费掉触摸事件
return true;
}
重写EditView的dispatchTouchEvent
事件 默认点击就获取焦点弹出键盘 然后在消费掉触摸事件,不然双击EditView 会弹出选择复制光标
监听EditView输入框内容长度
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
password = s.toString();
passWordCount = s.length();
//是否输入完成
isComplete = passWordCount == password_max_len;
if (passWordChangeListener != null)
passWordChangeListener.onTextChange();
invalidate();
}
添加addTextChangedListener
监听文字变化 然后再调用 invalidate()
绘制背景
背景绘制onDraw函数
首先绘制的是背景因为背景是填充完全 所以设置参数 passwordPaint.setStyle(Paint.Style.FILL);
/**
* rectStrokeF 分别是上下左右的坐标参数 在初始化参数里面初始化玩
* passwordRadius 圆角
* passwordPaint Paint配置 设置颜色等参数
**/
canvas.drawRoundRect(rectStrokeF, passwordRadius, passwordRadius, passwordPaint);
再者绘制边框和分割线条颜色 为了让获取焦点与取消焦点有区别 所以设置了两种颜色
//是否获取焦点
if (isFocused()) {
passwordPaint.setColor(lineFocusColor);
} else {
passwordPaint.setColor(lineColor);
}
绘制边框线条 即一个空心得圆角矩形 passwordPaint.setStyle(Paint.Style.STROKE);
设置空心
passwordPaint.setStrokeWidth(1);
passwordPaint.setStyle(Paint.Style.STROKE);
canvas.drawRoundRect(rectF, passwordRadius, passwordRadius, passwordPaint);
绘制分割线条根据颜色来设置
计算出平均间隔 然后在循环调用canvas.drawLine()
绘制线条 至于height - 3 是高度填充满的话底部会出现一届扭曲 就这样解决
int w = width / password_max_len;
for (int i = 0; i < password_max_len; i++) {
canvas.drawLine(i * w + w, 1, i * w + w + 1, height - 3, passwordPaint);
}
绘制密码圆点
int h = getHeight() / 2;
if (isFocusable()) {
passwordRoundPaint.setColor(circleFocusColor);
} else {
passwordRoundPaint.setColor(circleColor);
}
//密码点
for (int i = 0; i < passWordCount; i++) {
canvas.drawCircle(i * w + w / 2, h, circleSize, passwordRoundPaint);
}
同样为了区分 获取焦点和失去焦点的颜色是不一样的 然后在根据已输入的密码颜色绘制 对应数量的圆点
完整的onDraw
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//背景
passwordPaint.setColor(backgroundColor);
passwordPaint.setStyle(Paint.Style.FILL);
canvas.drawRoundRect(rectStrokeF, passwordRadius, passwordRadius, passwordPaint);
//边框颜色
if (isFocused()) {
passwordPaint.setColor(lineFocusColor);
} else {
passwordPaint.setColor(lineColor);
}
passwordPaint.setStrokeWidth(1);
passwordPaint.setStyle(Paint.Style.STROKE);
canvas.drawRoundRect(rectF, passwordRadius, passwordRadius, passwordPaint);
int w = width / password_max_len;
int h = getHeight() / 2;
for (int i = 0; i < password_max_len; i++) {
canvas.drawLine(i * w + w, 1, i * w + w + 1, height - 3, passwordPaint);
}
if (isFocusable()) {
passwordRoundPaint.setColor(circleFocusColor);
} else {
passwordRoundPaint.setColor(circleColor);
}
//密码点
for (int i = 0; i < passWordCount; i++) {
canvas.drawCircle(i * w + w / 2, h, circleSize, passwordRoundPaint);// 小圆
}
}
这样就自定义完成
Attributes
name | format | java code |
---|---|---|
edit_background | color|reference | public void setBackground(int background) |
edit_line_color | color|reference | public void setLineColor(int lineColor) |
edit_line_focus_color | color|reference | public void setLineFocusColor(int lineFocusColor) |
edit_circle_color | color|reference | public void setCircleColor(int circleColor) |
edit_circle_focus_color | color|reference | public void setCircleFocusColor(int circleFocusColor) |
edit_background_radius | integer | public void setPasswordRadius(int passwordRadius) |
edit_circle_size | dimension|integer | public void setCircleSize(int circleSize) |
edit_max_length | integer | public void setMaxLen(int password_max_len) |
XML
<com.chaek.android.passwordeditview.PassWordEditView
android:layout_width="match_parent"
android:layout_height="40dp"
app:edit_background="#ffF5F7F9"
app:edit_background_radius="3dp"
app:edit_circle_color="#fa760a"
app:edit_circle_size="5dp"
app:edit_line_color="#ffE1E4E8"
app:edit_line_focus_color="#ffBEC5CD"
app:edit_max_length="6" />