1.密碼輸入框 attrs.xml PasswordEditText 目前的效果就是點擊之後會彈出系統的鍵盤,實現了基本的效果,接下來我們再加入監聽也就說當密碼輸入完成我們需要回調監聽。 2.自定義鍵盤: ui_customer_keyboard.xml: 1 <?xml version="1.0" ...
1.密碼輸入框
attrs.xml
<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="PasswordEditText"> <!-- 密碼的個數 --> <attr name="passwordNumber" format="integer"/> <!-- 密碼圓點的半徑 --> <attr name="passwordRadius" format="dimension" /> <!-- 密碼圓點的顏色 --> <attr name="passwordColor" format="color" /> <!-- 分割線的顏色 --> <attr name="divisionLineColor" format="color" /> <!-- 分割線的大小 --> <attr name="divisionLineSize" format="color" /> <!-- 背景邊框的顏色 --> <attr name="bgColor" format="color" /> <!-- 背景邊框的大小 --> <attr name="bgSize" format="dimension" /> <!-- 背景邊框的圓角大小 --> <attr name="bgCorner" format="dimension"/> </declare-styleable> </resources>
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 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:id="@+id/activity_main" 4 android:layout_width="match_parent" 5 android:layout_height="wrap_content" 6 android:background="#EBEBEB" 7 android:orientation="vertical"> 8 9 <LinearLayout 10 android:layout_width="match_parent" 11 android:layout_height="wrap_content"> 12 13 <TextView 14 android:layout_width="0dp" 15 android:layout_height="wrap_content" 16 android:layout_marginRight="1dp" 17 android:layout_weight="1" 18 android:background="#FFFFFF" 19 android:gravity="center" 20 android:padding="20dp" 21 android:text="1" /> 22 23 <TextView 24 android:layout_width="0dp" 25 android:layout_height="wrap_content" 26 android:layout_marginRight="1dp" 27 android:layout_weight="1" 28 android:background="#FFFFFF" 29 android:gravity="center" 30 android:padding="20dp" 31 android:text="2" /> 32 33 <TextView 34 android:layout_width="0dp" 35 android:layout_height="wrap_content" 36 android:layout_weight="1" 37 android:background="#FFFFFF" 38 android:gravity="center" 39 android:padding="20dp" 40 android:text="3" /> 41 </LinearLayout> 42 43 <LinearLayout 44 android:layout_width="match_parent" 45 android:layout_height="wrap_content" 46 android:layout_marginTop="1dp"> 47 48 <TextView 49 android:layout_width="0dp" 50 android:layout_height="wrap_content" 51 android:layout_marginRight="1dp" 52 android:layout_weight="1" 53 android:background="#FFFFFF" 54 android:gravity="center" 55 android:padding="20dp" 56 android:text="4" /> 57 58 <TextView 59 android:layout_width="0dp" 60 android:layout_height="wrap_content" 61 android:layout_marginRight="1dp" 62 android:layout_weight="1" 63 android:background="#FFFFFF" 64 android:gravity="center" 65 android:padding="20dp" 66 android:text="5" /> 67 68 <TextView 69 android:layout_width="0dp" 70 android:layout_height="wrap_content" 71 android:layout_weight="1" 72 android:background="#FFFFFF" 73 android:gravity="center" 74 android:padding="20dp" 75 android:text="6" /> 76 </LinearLayout> 77 78 <LinearLayout 79 android:layout_width="match_parent" 80 android:layout_height="wrap_content" 81 android:layout_marginTop="1dp"> 82 83 <TextView 84 android:layout_width="0dp" 85 android:layout_height="wrap_content" 86 android:layout_marginRight="1dp" 87 android:layout_weight="1" 88 android:background="#FFFFFF" 89 android:gravity="center" 90 android:padding="20dp" 91 android:text="7" /> 92 93 <TextView 94 android:layout_width="0dp" 95 android:layout_height="wrap_content" 96 android:layout_marginRight="1dp" 97 android:layout_weight="1" 98 android:background="#FFFFFF" 99 android:gravity="center" 100 android:padding="20dp" 101 android:text="8" /> 102 103 <TextView 104 android:layout_width="0dp" 105 android:layout_height="wrap_content" 106 android:layout_weight="1" 107 android:background="#FFFFFF" 108 android:gravity="center" 109 android:padding="20dp" 110 android:text="9" /> 111 112 </LinearLayout> 113 114 <LinearLayout 115 android:layout_width="match_parent" 116 android:layout_height="wrap_content" 117 android:layout_marginTop="1dp" 118 android:orientation="horizontal"> 119 120 <TextView 121 android:layout_width="0dp" 122 android:layout_height="wrap_content" 123 android:layout_marginRight="1dp" 124 android:layout_weight="1" 125 android:gravity="center" 126 android:padding="20dp" /> 127 128 <TextView 129 android:layout_width="0dp" 130 android:layout_height="wrap_content" 131 android:layout_marginRight="1dp" 132 android:layout_weight="1" 133 android:background="#FFFFFF" 134 android:gravity="center" 135 android:padding="20dp" 136 android:text="0" /> 137 138 <ImageView 139 android:layout_width="0dp" 140 android:layout_height="wrap_content" 141 android:layout_weight="1" 142 android:gravity="center" 143 android:padding="15dp" 144 android:layout_gravity="center_vertical" 145 android:src="@drawable/customer_password_keyboard_delete" /> 146 </LinearLayout> 147 </LinearLayout>View Code
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 @Override 35 public void onClick(View v) { 36 View clickView = v; 37 if (clickView instanceof TextView) { 38 // 如果點擊的是TextView 39 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
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="wrap_content" xmlns:app="http://schemas.android.com/apk/res-auto" android:background="#f7f7f7" android:orientation="vertical"> <com.hc.passwordedittext.PasswordEditText android:id="@+id/password_edit_text" android:layout_width="match_parent" android:layout_marginTop="23dp" android:layout_marginRight="45dp" android:background="@null" android:padding="10dp" app:bgCorner="3dp" android:layout_marginLeft="45dp" android:layout_height="wrap_content" /> <com.hc.passwordedittext.CustomerKeyboard android:id="@+id/custom_key_board" android:layout_marginTop="23dp" android:layout_width="match_parent" android:layout_height="wrap_content"/> </LinearLayout>
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 @Override 22 public void click(String number) { 23 mPasswordEditText.addPassword(number); 24 } 25 26 /** 27 * 鍵盤刪除點擊監聽回調方法 28 */ 29 @Override 30 public void delete() { 31 mPasswordEditText.deleteLastPassword(); 32 } 33 34 /** 35 * 密碼輸入完畢回調方法 36 */ 37 @Override 38 public void passwordFull(String password) { 39 Toast.makeText(this, "密碼填充完畢:" + password, Toast.LENGTH_SHORT).show(); 40 } 41 }
https://github.com/HCDarren/PasswordEditText