1.密码输入框
attrs.xml
PasswordEditText
public class PasswordEditText extends EditText { // 画笔 private Paint mPaint; // 一个密码所占的宽度 private int mPasswordItemWidth; // 密码的个数默认为6位数 private int mPasswordNumber = 6; // 背景边框颜色 private int mBgColor = Color.parseColor("#d1d2d6"); // 背景边框大小 private int mBgSize = 1; // 背景边框圆角大小 private int mBgCorner = 0; // 分割线的颜色 private int mDivisionLineColor = mBgColor; // 分割线的大小 private int mDivisionLineSize = 1; // 密码圆点的颜色 private int mPasswordColor = mDivisionLineColor; // 密码圆点的半径大小 private int mPasswordRadius = 4; private PasswordFullListener mListener; public PasswordEditText(Context context) { this(context, null); } public PasswordEditText(Context context, AttributeSet attrs) { super(context, attrs); initPaint(); initAttributeSet(context, attrs); // 设置输入模式是密码 setInputType(EditorInfo.TYPE_TEXT_VARIATION_PASSWORD); // 不显示光标 setCursorVisible(false); } /** * 初始化属性 */ private void initAttributeSet(Context context, AttributeSet attrs) { TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.PasswordEditText); // 获取大小 mDivisionLineSize = (int) array.getDimension(R.styleable.PasswordEditText_divisionLineSize, dip2px(mDivisionLineSize)); mPasswordRadius = (int) array.getDimension(R.styleable.PasswordEditText_passwordRadius, dip2px(mPasswordRadius)); mBgSize = (int) array.getDimension(R.styleable.PasswordEditText_bgSize, dip2px(mBgSize)); mBgCorner = (int) array.getDimension(R.styleable.PasswordEditText_bgCorner, 0); // 获取颜色 mBgColor = array.getColor(R.styleable.PasswordEditText_bgColor, mBgColor); mDivisionLineColor = array.getColor(R.styleable.PasswordEditText_divisionLineColor, mDivisionLineColor); mPasswordColor = array.getColor(R.styleable.PasswordEditText_passwordColor, mDivisionLineColor); array.recycle(); } /** * 初始化画笔 */ private void initPaint() { mPaint = new Paint(); mPaint.setAntiAlias(true); mPaint.setDither(true); } /** * dip 转 px */ private int dip2px(int dip) { return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dip, getResources().getDisplayMetrics()); } @Override protected void onDraw(Canvas canvas) { int passwordWidth = getWidth() - (mPasswordNumber - 1) * mDivisionLineSize; mPasswordItemWidth = passwordWidth / mPasswordNumber; // 绘制背景 drawBg(canvas); // 绘制分割线 drawDivisionLine(canvas); // 绘制密码 drawHidePassword(canvas); } /** * 绘制背景 */ private void drawBg(Canvas canvas) { mPaint.setColor(mBgColor); // 设置画笔为空心 mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeWidth(mBgSize); RectF rectF = new RectF(mBgSize, mBgSize, getWidth() - mBgSize, getHeight() - mBgSize); // 如果没有设置圆角,就画矩形 if (mBgCorner == 0) { canvas.drawRect(rectF, mPaint); } else { // 如果有设置圆角就画圆矩形 canvas.drawRoundRect(rectF, mBgCorner, mBgCorner, mPaint); } } /** * 绘制隐藏的密码 */ private void drawHidePassword(Canvas canvas) { int passwordLength = getText().length(); mPaint.setColor(mPasswordColor); // 设置画笔为实心 mPaint.setStyle(Paint.Style.FILL); for (int i = 0; i < passwordLength; i++) { int cx = i * mDivisionLineSize + i * mPasswordItemWidth + mPasswordItemWidth / 2 + mBgSize; canvas.drawCircle(cx, getHeight() / 2, mPasswordRadius, mPaint); } // 判断密码是否填充完毕 if (passwordLength >= mPasswordNumber) { // 代表密码已经填充满了 if (mListener != null) { mListener.passwordFull(getText().toString().trim()); } } } /** * 绘制分割线 */ private void drawDivisionLine(Canvas canvas) { mPaint.setStrokeWidth(mDivisionLineSize); mPaint.setColor(mDivisionLineColor); for (int i = 0; i < mPasswordNumber - 1; i++) { int startX = (i + 1) * mDivisionLineSize + (i + 1) * mPasswordItemWidth + mBgSize; canvas.drawLine(startX, mBgSize, startX, getHeight() - mBgSize, mPaint); } } /** * 添加密码 */ public void addPassword(String number) { number = getText().toString().trim() + number; if (number.length() > mPasswordNumber) { return; } setText(number); } /** * 删除最后一位密码 */ public void deleteLastPassword() { String currentText = getText().toString().trim(); if (TextUtils.isEmpty(currentText)) { return; } currentText = currentText.substring(0, currentText.length() - 1); setText(currentText); } /** * 设置密码填充满的监听 */ public void setOnPasswordFullListener(PasswordFullListener listener) { this.mListener = listener; } /** * 密码已经全部填满 */ public interface PasswordFullListener { public void passwordFull(String password); }}
目前的效果就是点击之后会弹出系统的键盘,实现了基本的效果,接下来我们再加入监听也就说当密码输入完成我们需要回调监听。
2.自定义键盘:
ui_customer_keyboard.xml:
1 28 9 14712 13 42 4322 23 32 33 41 47 48 77 7857 58 67 68 76 82 83 113 11492 93 102 103 111 112 119 120 127 128 137 138 146
CustomerKeyboard.java:
1 public class CustomerKeyboard extends LinearLayout implements View.OnClickListener { 2 private CustomerKeyboardClickListener mListener; 3 4 public CustomerKeyboard(Context context) { 5 this(context, null); 6 } 7 8 public CustomerKeyboard(Context context, AttributeSet attrs) { 9 this(context, attrs, 0);10 }11 12 public CustomerKeyboard(Context context, AttributeSet attrs, int defStyleAttr) {13 super(context, attrs, defStyleAttr);14 inflate(context, R.layout.ui_customer_keyboard, this);15 setChildViewOnclick(this);16 }17 18 /**19 * 设置键盘子View的点击事件20 */21 private void setChildViewOnclick(ViewGroup parent) {22 int childCount = parent.getChildCount();23 for (int i = 0; i < childCount; i++) {24 // 不断的递归设置点击事件25 View view = parent.getChildAt(i);26 if (view instanceof ViewGroup) {27 setChildViewOnclick((ViewGroup) view);28 continue;29 }30 view.setOnClickListener(this);31 }32 }33 34 @Override35 public void onClick(View v) {36 View clickView = v;37 if (clickView instanceof TextView) {38 // 如果点击的是TextView39 String number = ((TextView) clickView).getText().toString();40 if (!TextUtils.isEmpty(number)) {41 if (mListener != null) {42 // 回调43 mListener.click(number);44 }45 }46 } else if (clickView instanceof ImageView) {47 // 如果是图片那肯定点击的是删除48 if (mListener != null) {49 mListener.delete();50 }51 }52 }53 54 /**55 * 设置键盘的点击回调监听56 */57 public void setOnCustomerKeyboardClickListener(CustomerKeyboardClickListener listener) {58 this.mListener = listener;59 }60 61 /**62 * 点击键盘的回调监听63 */64 public interface CustomerKeyboardClickListener {65 public void click(String number);66 public void delete();67 }68 }
3.最后的测试
activity_main.xml
MainActivity.java
1 public class MainActivity extends Activity implements CustomerKeyboard.CustomerKeyboardClickListener, 2 PasswordEditText.PasswordFullListener{ 3 4 private CustomerKeyboard mCustomerKeyboard; 5 private PasswordEditText mPasswordEditText; 6 7 @Override 8 protected void onCreate(Bundle savedInstanceState) { 9 super.onCreate(savedInstanceState);10 setContentView(R.layout.activity_main);11 mPasswordEditText = (PasswordEditText) findViewById(R.id.password_et);12 mCustomerKeyboard = (CustomerKeyboard) findViewById(R.id.custom_key_board);13 // 设置监听14 mCustomerKeyboard.setOnCustomerKeyboardClickListener(this);15 mPasswordEditText.setOnPasswordFullListener(this);16 }17 18 /**19 * 键盘数字点击监听回调方法20 */21 @Override22 public void click(String number) {23 mPasswordEditText.addPassword(number);24 }25 26 /**27 * 键盘删除点击监听回调方法28 */29 @Override30 public void delete() {31 mPasswordEditText.deleteLastPassword();32 }33 34 /**35 * 密码输入完毕回调方法36 */37 @Override38 public void passwordFull(String password) {39 Toast.makeText(this, "密码填充完毕:" + password, Toast.LENGTH_SHORT).show();40 }41 }