按照惯例先上效果图:
⚠️分析:
一、需要调用输入数字输入框
二、对输入框的监控
三、画圆角的矩形
四、画分割线
五、画密码的原点
思路:
EditText符合前两个需求,但是我们不想显示输入内容与默认的密码样式。所以我们可以自定义View继承EdiText。来实现下面三种需求。
一、我们只需要EditText调用数字输入框和对文字的监控特性即可,其他的我们自定义
android:inputType="number"
二、我们在onDraw方法里画一个圆角矩形画笔为填充模式覆盖住原有EdiText的显示效果,再画一个小一点圆角矩形在刚出的圆角矩形里面,来实现圆角矩形的边框。(其实有各种实现方式)
三、然后根据密码长度来画“密码长度-1”个分割线
四、重写监听文字变化来画密码的圆点。
代码如下:代码里有详细注释
public class PasswordInputView extends EditText {
private String TAG = "PasswordInputView";
private Context mContext;
private int passwordSize = 6;//密码的个数这里是默认值,也可以通过自定义属性来设置其他数值
private int borderWidth = 6;//密码输入框的边框宽度px
private int borderRadius = 6;//密码输入框矩形圆角的半径
private int borderColor = 0xff333333;//密码输入框边框的颜色
private int passwordWidth = 12;//密码的宽度
private int passwordColor = 0xff000000;//密码的颜色
private int defaultSplitLineWidth = 3; //px
private int allPasswordWidth;//控件的总宽度
private int allPasswordHight;//控件的总高度
private Paint mPaint;//边框画笔
private Paint pwPaint;//密码画笔
private int passwordTextSize;//输入密码的个数
private String password;//密码
private onPasswordChangedListener onPasswordChangedListener;
public void setOnPasswordChangedListener(PasswordInputView.onPasswordChangedListener onPasswordChangedListener) {
this.onPasswordChangedListener = onPasswordChangedListener;
}
//获取密码
public String getPassword() {
return password;
}
//注意 :只能复写这个构造函数,切只能在这里初始化,不然你会发现EditText的特性就没有来
public PasswordInputView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {
mContext = context;
/**
* 初始化各种自定义属性
* */
TypedArray typedArray = mContext.obtainStyledAttributes(attrs,R.styleable.PasswordInputView);
passwordSize = typedArray.getInt(R.styleable.PasswordInputView_passwordLength, passwordSize);
borderWidth = typedArray.getDimensionPixelSize(R.styleable.PasswordInputView_borderWidth, borderWidth);
borderRadius = typedArray.getDimensionPixelSize(R.styleable.PasswordInputView_borderRadius, borderRadius);
borderColor = typedArray.getColor(R.styleable.PasswordInputView_borderColor, borderColor);
passwordWidth = typedArray.getDimensionPixelSize(R.styleable.PasswordInputView_passwordWidth, passwordWidth);
passwordColor = typedArray.getColor(R.styleable.PasswordInputView_passwordColor, passwordColor);
Log.d(TAG,"borderRadius:"+borderRadius);
Log.d(TAG,"passwordSize:"+passwordSize);
typedArray.recycle();
//初始化边框画笔
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setStrokeWidth(borderWidth);
//初始化密码画笔
pwPaint = new Paint();
pwPaint.setAntiAlias(true);
pwPaint.setStyle(Paint.Style.FILL);
pwPaint.setColor(passwordColor);
pwPaint.setStrokeWidth(passwordWidth);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
Log.d(TAG, "onSizeChanged");
allPasswordWidth = w;
allPasswordHight = h;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Log.d(TAG, "onDraw");
Log.d(TAG, "allPasswordWidth:" + allPasswordWidth);
Log.d(TAG, "borderRadius:" + borderRadius);
//画一个矩形遮住显示的文字
mPaint.setColor(borderColor);
canvas.drawRoundRect(0, 0, allPasswordWidth, allPasswordHight, borderRadius, borderRadius, mPaint);
//再画一个白色矩形这种上面的矩形内部,形成假的边框
mPaint.setColor(Color.WHITE);
canvas.drawRoundRect(defaultSplitLineWidth, defaultSplitLineWidth,
allPasswordWidth - defaultSplitLineWidth, allPasswordHight - defaultSplitLineWidth,borderRadius,borderRadius, mPaint);
//画分割线
int lineStartAndEndx = allPasswordWidth / passwordSize;
int lineStarty = 0;
int lineendy = allPasswordHight;
mPaint.setColor(borderColor);
mPaint.setStrokeWidth(defaultSplitLineWidth);
for (int i = 1; i < passwordSize; i++) {
canvas.drawLine(lineStartAndEndx, lineStarty, lineStartAndEndx, lineendy, mPaint);
lineStartAndEndx += allPasswordWidth / passwordSize;
}
//画密码圆
int circleX = allPasswordWidth / passwordSize / 2;
int circleY = allPasswordHight / 2;
if (passwordTextSize > 0) {
for (int i = 0; i < passwordTextSize; i++) {
canvas.drawCircle(circleX, circleY, passwordWidth, pwPaint);
circleX += allPasswordWidth / passwordSize;
}
}
}
@Override
protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) {
super.onTextChanged(text, start, lengthBefore, lengthAfter);
//监听文字变化大于密码设定长度不记录
Log.d(TAG,"onTextChanged:"+passwordSize);
if (text.length() <= passwordSize){
passwordTextSize = text.length();
password = text.toString();
if (onPasswordChangedListener != null)
onPasswordChangedListener.setPasswordChanged();
}else {
text = password;
}
invalidate();
}
//设置监听密码变化
public interface onPasswordChangedListener {
public void setPasswordChanged();
}
}
自定义属性文件attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="PasswordInputView">
<attr name="passwordLength" format="integer"/>
<attr name="borderWidth" format="dimension"/>
<attr name="borderRadius" format="dimension"/>
<attr name="borderColor" format="color"/>
<attr name="passwordWidth" format="dimension"/>
<attr name="passwordColor" format="color"/>
</declare-styleable>
</resources>
布局中的使用
android:maxLength=“6” 密码的限制长度
app:passwordLength=“6” 密码的中长度
这两个要设置一样,这点其实可以再优化,设置一个值即可。
<com.goodboy.mile.View.PasswordInputView
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:id="@+id/password_view"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="@null"
android:cursorVisible="false"
android:inputType="number"
android:maxLength="6"
app:passwordLength="6"
app:borderWidth="10dp"
app:borderRadius="8dp"
app:passwordWidth="6dp"
app:passwordColor="#ffaaaaaa"/>