1、效果图:
2、代码:
attr.xml
<declare-styleable name="PasswordView">
<attr name="pv_color" format="color|reference" />
<attr name="pv_background_color" format="color|reference" />
<attr name="pv_stroke_color" format="color|reference" />
<attr name="pv_stroke_width" format="dimension" />
<attr name="pv_password_length" format="integer|reference" />
</declare-styleable>
view源码:
package exam.org.jsc.password.view;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
import exam.org.jsc.password.R;
/**
* Created by Justin Qin on 3/25/2017.
*/
public class PasswordView extends View {
Paint mPaint;
int color;
int backgroundColor;
int strokeColor;
int strokeWidth;
String password = "";
int passwordLength;
OnPasswordChangedListener changedListener;
public PasswordView(Context context) {
this(context, null);
}
public PasswordView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public PasswordView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.PasswordView);
color = array.getColor(R.styleable.PasswordView_pv_color, Color.BLACK);
backgroundColor = array.getColor(R.styleable.PasswordView_pv_background_color, Color.WHITE);
strokeColor = array.getColor(R.styleable.PasswordView_pv_stroke_color, Color.BLACK);
strokeWidth = array.getDimensionPixelSize(R.styleable.CloseView_cv_stroke_width, 1);
passwordLength = array.getInt(R.styleable.PasswordView_pv_password_length, 6);
array.recycle();
init();
}
private void init(){
mPaint = new Paint();
mPaint.setAntiAlias(true);
}
public void addOnPasswordChangedListener(OnPasswordChangedListener changedListener) {
this.changedListener = changedListener;
}
public void input(String txt){
if (password.length() >= passwordLength)
return;
password += txt;
postInvalidate();
if (changedListener == null)
return;
changedListener.onPasswordChanged(password);
if (password.length() >= passwordLength)
changedListener.onPasswordFinish(password);
}
public void delete(){
if (password.length() <= 0)
return;
password = password.substring(0, password.length() -1);
postInvalidate();
if (changedListener != null)
changedListener.onPasswordChanged(password);
}
public void clearPassword(){
password = "";
postInvalidate();
if (changedListener != null)
changedListener.onPasswordChanged(password);
}
public String getPassword() {
return password;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(getDefaultSize(0, widthMeasureSpec), getDefaultSize(0, heightMeasureSpec));
int widthSize = getMeasuredWidth();
int heightSize = getMeasuredHeight();
//把宽度分成passwordLength等份
widthMeasureSpec = MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.EXACTLY);
heightMeasureSpec = MeasureSpec.makeMeasureSpec(widthSize / passwordLength, MeasureSpec.EXACTLY);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int width = getWidth();
int height = getHeight();
int stepWidth = width / passwordLength;
mPaint.setColor(backgroundColor);
mPaint.setStyle(Paint.Style.FILL);
canvas.drawRect(0, 0, width, height, mPaint);
mPaint.setColor(strokeColor);
mPaint.setStrokeWidth(strokeWidth);
mPaint.setStyle(Paint.Style.STROKE);
canvas.drawRect(0, 0, width - strokeWidth, height - strokeWidth, mPaint);
for (int i = 1; i < passwordLength; i++) {
canvas.drawLine(stepWidth * i, 0, stepWidth * i, height, mPaint);
}
mPaint.setColor(color);
mPaint.setStyle(Paint.Style.FILL);
int radius = stepWidth / 8;
int len = password.length() > passwordLength ? passwordLength : password.length();
for (int i = 0; i < len; i++) {
canvas.drawCircle(stepWidth / 2 + stepWidth * i, height / 2, radius, mPaint);
}
}
public interface OnPasswordChangedListener {
void onPasswordChanged(String password);
void onPasswordFinish(String password);
}
}
3、使用:
layout.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main2"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="exam.org.jsc.password.activity.AboutActivity">
<include layout="@layout/title_bar" />
<exam.org.jsc.password.view.PasswordView
android:id="@+id/et_password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="40dp"
android:layout_marginLeft="40dp"
android:layout_marginRight="40dp"
app:pv_color="@color/colorAccent" />
<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="40dp"
android:layout_gravity="center_horizontal"
android:columnCount="4"
android:orientation="horizontal"
android:rowCount="3">
<Button
android:id="@+id/btn_01"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="1" />
<Button
android:id="@+id/btn_02"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="2" />
<Button
android:id="@+id/btn_03"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="3" />
<Button
android:id="@+id/btn_04"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="4" />
<Button
android:id="@+id/btn_05"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="5" />
<Button
android:id="@+id/btn_06"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="6" />
<Button
android:id="@+id/btn_07"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="7" />
<Button
android:id="@+id/btn_08"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="8" />
<Button
android:id="@+id/btn_09"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="9" />
<Button
android:id="@+id/btn_00"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="0" />
<Button
android:id="@+id/btn_10"
android:layout_columnSpan="2"
android:layou`
_gravity="fill"
android:text="delete" />
</GridLayout>
</LinearLayout>
Activity
package exam.org.jsc.password.activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import exam.org.jsc.password.R;
import exam.org.jsc.password.view.PasswordView;
public class InputPasswordActivity extends BaseActivity {
private final int[] ids = {
R.id.btn_00,
R.id.btn_01,
R.id.btn_02,
R.id.btn_03,
R.id.btn_04,
R.id.btn_05,
R.id.btn_06,
R.id.btn_07,
R.id.btn_08,
R.id.btn_09,
R.id.btn_10
};
PasswordView mPasswordView;
private Button[] buttons = new Button[ids.length];
private View.OnClickListener listener = new View.OnClickListener() {
@Override
public void onClick(View v) {
if (v.getId() == R.id.btn_10){
mPasswordView.delete();
} else {
Button button = (Button) v;
String input = button.getText().toString();
mPasswordView.input(input);
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_input_password);
setStatusBarBackground();
initTitleBar("InputPassword", new View.OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
mPasswordView = (PasswordView) findViewById(R.id.et_password);
mPasswordView.addOnPasswordChangedListener(new PasswordView.OnPasswordChangedListener() {
@Override
public void onPasswordChanged(String password) {
}
@Override
public void onPasswordFinish(String password) {
showShortToast(password);
}
});
for (int i = 0; i < ids.length; i++) {
buttons[i] = (Button) findViewById(ids[i]);
buttons[i].setOnClickListener(listener);
}
}
}
谢谢您的惠顾,code有不足的地方请在评论里回复(或者联系我)。
QQ:1006368252