实现效果图:
实现流程:
1、定义6位密码输入View思路:要绘制边框矩形,绘制分割线,绘制圆点。绘制圆的数目要与字符串的长度有关,添加或者删除都要修改字符串,输入6位后就是要关闭弹框,拿到密码,做判断工作了。
public class PasswordEditText extends AppCompatEditText { // 画笔 private Paint mPaint; // 一个密码所占的宽度 private int mPasswordItemWidth; // 密码的个数默认为6位数 private int mPasswordNumber = 6; // 背景边框颜色 private int mBgColor = Color.parseColor("#FFDDDDDD"); // 背景边框大小 private int mBgSize = 1; // 背景边框圆角大小 private int mBgCorner = 8; // 分割线的颜色 private int mDivisionLineColor = mBgColor; // 分割线的大小 private int mDivisionLineSize = 1; // 密码圆点的颜色 private int mPasswordColor = Color.parseColor("#FF000000"); // 密码圆点的半径大小 private int mPasswordRadius = 6; public PasswordEditText(Context context) { this(context, null); } public PasswordEditText(Context context, AttributeSet attrs) { super(context, attrs); initAttributeSet(context, attrs); initPaint(); // 默认只能够设置数字和字母 setInputType(EditorInfo.TYPE_TEXT_VARIATION_PASSWORD); } /** * 初始化画笔 */ private void initPaint() { mPaint = new Paint(); // 抗锯齿 mPaint.setAntiAlias(true); // 防抖动 mPaint.setDither(true); } /** * 初始化属性 */ 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, mBgCorner); // 获取边框颜色 mBgColor = array.getColor(R.styleable.PasswordEditText_bgColor, mBgColor); // 分割线颜色 mDivisionLineColor = array.getColor(R.styleable.PasswordEditText_divisionLineColor, mDivisionLineColor); //圆点颜色 mPasswordColor = array.getColor(R.styleable.PasswordEditText_passwordColor, mPasswordColor); array.recycle(); } /** * dip 转 px */ private float dip2px(int dip) { return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dip, getResources().getDisplayMetrics()); } @Override protected void onDraw(Canvas canvas) { // 一个密码的宽度 [View宽度 - 边框的宽度(背景边框与分割线)]/6 mPasswordItemWidth = (getWidth() - 2 * mBgSize - (mPasswordNumber - 1) * mDivisionLineSize) / mPasswordNumber; // 画背景 drawBg(canvas); // 画分割线 drawDivisionLine(canvas); // 画密码 drawPassword(canvas); // 当前密码是不是满了 if (mListener != null) { String password = getText().toString().trim(); if (password.length() >= mPasswordNumber) { mListener.passwordFull(password); } } } /** * 绘制密码 */ private void drawPassword(Canvas canvas) { // 密码绘制是实心 mPaint.setStyle(Paint.Style.FILL); // 设置密码的颜色 mPaint.setColor(mPasswordColor); // 获取当前text String text = getText().toString().trim(); // 获取密码的长度 int passwordLength = text.length(); // 不断的绘制密码 for (int i = 0; i < passwordLength; i++) { int cy = getHeight() / 2; int cx = mBgSize + i * mPasswordItemWidth + i * mDivisionLineSize + mPasswordItemWidth / 2; canvas.drawCircle(cx, cy, mPasswordRadius, mPaint); } } /** * 绘制分割线 */ private void drawDivisionLine(Canvas canvas) { // 给画笔设置大小 mPaint.setStrokeWidth(mDivisionLineSize); // 设置分割线的颜色 mPaint.setColor(mDivisionLineColor); //画竖线,x值不变 for (int i = 0; i < mPasswordNumber - 1; i++) { int startX = mBgSize + (i + 1) * mPasswordItemWidth + i * mDivisionLineSize; int startY = mBgSize; int endX = startX; int endY = getHeight() - mBgSize; canvas.drawLine(startX, startY, endX, endY, mPaint); } } /** * 绘制背景 */ private void drawBg(Canvas canvas) { //背景矩形 RectF rect = new RectF(mBgSize, mBgSize, getWidth() - mBgSize, getHeight() - mBgSize); // 给画笔设置大小 mPaint.setStrokeWidth(mBgSize); // 设置背景的颜色 mPaint.setColor(mBgColor); // 画空心 mPaint.setStyle(Paint.Style.STROKE); // 绘制背景 drawRect , drawRoundRect , // 如果有圆角那么就绘制drawRoundRect,否则绘制drawRect if (mBgCorner == 0) { canvas.drawRect(rect, mPaint); } else { //rx:x方向上的圆角半径。ry:y方向上的圆角半径。 canvas.drawRoundRect(rect, mBgCorner, mBgCorner, mPaint); } } /** * 添加一个密码 */ public void addPassword(String number) { // 把之前的密码取出来 String password = getText().toString().trim(); if (password.length() >= mPasswordNumber) { // 密码不能超过当前密码个输 return; } // 密码叠加 password += number; setText(password); } /** * 删除最后一位密码 */ public void deleteLastPassword() { String password = getText().toString().trim(); // 判断当前密码是不是空 if (TextUtils.isEmpty(password)) { return; } password = password.substring(0, password.length() - 1); setText(password); } // 设置当前密码是否已满的接口回掉 private PasswordFullListener mListener; public void setOnPasswordFullListener(PasswordFullListener listener) { this.mListener = listener; } public void clear() { setText(""); } /** * 密码已经全部填满 */ public interface PasswordFullListener { public void passwordFull(String password); }}
2、键盘View
思路:主要是点击数字后,拿到数字,在给PasswordEditText它。点击删除后,删除PasswordEditText里面的一个字符。逻辑都是在Dialog里面控制的。public class CustomerKeyboard extends LinearLayout implements View.OnClickListener { public CustomerKeyboard(Context context) { this(context, null); } public CustomerKeyboard(Context context, AttributeSet attrs) { this(context, attrs, 0); } public CustomerKeyboard(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); // 直接加载布局 inflate(context, R.layout.ui_customer_keyboard, this); setItemClickListener(this); } /** * 设置子View的ClickListener */ private void setItemClickListener(View view) { if (view instanceof ViewGroup) { ViewGroup viewGroup = (ViewGroup) view; int childCount = viewGroup.getChildCount(); for (int i = 0; i < childCount; i++) { //不断的递归给里面所有的View设置OnClickListener View childView = viewGroup.getChildAt(i); setItemClickListener(childView); } } else { view.setOnClickListener(this); } } @Override public void onClick(View v) { if (v instanceof TextView) { if ("删除".equals(((TextView) v).getText().toString().trim())) { // 点击的是删除 if (mListener != null) { mListener.delete(); } } else { // 点击的是数字 String number = ((TextView) v).getText().toString().trim(); if (mListener != null) { mListener.click(number); } } } } // 设置点击回掉监听 private CustomerKeyboardClickListener mListener; public void setOnCustomerKeyboardClickListener(CustomerKeyboardClickListener listener) { this.mListener = listener; } /** * 点击键盘的回调监听 */ public interface CustomerKeyboardClickListener { public void click(String number); public void delete(); }}
3、对话框/** * 支付密码对话框 */public class PayPWDialogFragment extends DialogFragment implements CustomerKeyboard.CustomerKeyboardClickListener, PasswordEditText.PasswordFullListener { private PasswordEditText mPasswordEt; private OnCompleteListener mOnCompleteListener; private OnCancelListener mOnCancelListener; private static PayPWDialogFragment payPWDialogFragment; //写一个静态方法产生实例 public static PayPWDialogFragment newInstance() { if (payPWDialogFragment == null) { payPWDialogFragment = new PayPWDialogFragment(); } return payPWDialogFragment; } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.pay_password_dialog_layout, container, false); mPasswordEt = (PasswordEditText) view.findViewById(R.id.password_et); CustomerKeyboard mCustomerKeyboard = view.findViewById(R.id.custom_key_board); mCustomerKeyboard.setOnCustomerKeyboardClickListener(this); mPasswordEt.setEnabled(false); mPasswordEt.setOnPasswordFullListener(this); return view; } @Override public void onCreate(Bundle savedInstanceState) { //此处可以设置Dialog的style等等 super.onCreate(savedInstanceState); } @Override public Dialog onCreateDialog(Bundle savedInstanceState) { Dialog dialog = new Dialog(getActivity(), R.style.CustomDialog); dialog.requestWindowFeature(Window.FEATURE_NO_TITLE); dialog.setContentView(R.layout.pay_password_dialog_layout); dialog.setCanceledOnTouchOutside(false); /** * 设置宽度全屏,要设置在show的后面 */ WindowManager.LayoutParams layoutParams = dialog.getWindow().getAttributes(); layoutParams.gravity = Gravity.BOTTOM; layoutParams.width = WindowManager.LayoutParams.MATCH_PARENT; layoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT; dialog.getWindow().getDecorView().setPadding(0, 0, 0, 0); dialog.getWindow().setAttributes(layoutParams); return dialog; } @Override public void click(String number) { mPasswordEt.addPassword(number); } @Override public void delete() { mPasswordEt.deleteLastPassword(); } @Override public void passwordFull(String password) { if (mOnCompleteListener != null) mOnCompleteListener.onComplete(password); dismiss(); mPasswordEt.clear(); } public interface OnCompleteListener { void onComplete(String content); } public interface OnCancelListener { void onCancel(); } public PayPWDialogFragment setOnCompleteListener(OnCompleteListener listener) { this.mOnCompleteListener = listener; return this; } public PayPWDialogFragment setOnCancelListener(OnCancelListener listener) { this.mOnCancelListener = listener; return this; }}
4、使用PayPWDialogFragment.newInstance().setOnCompleteListener(new PayPWDialogFragment.OnCompleteListener() { @Override public void onComplete(String content) { } }).show(getFragmentManager(), "payPWDialogFragment");
配置: <style name="CustomDialog" parent="@android:style/Theme.Dialog"> <item name="android:windowFrame">@nullitem> <item name="android:windowIsFloating">trueitem> <item name="android:windowContentOverlay">@nullitem> <item name="android:windowAnimationStyle">@android:style/Animation.Dialogitem> <item name="android:windowSoftInputMode">stateUnspecified|adjustPanitem>style>
ui_customer_keyboard.xml<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#FFE6E6E6" android:orientation="vertical"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="1dp"> <TextView android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginRight="1dp" android:layout_weight="1" android:background="#FFFFFF" android:gravity="center" android:padding="8dp" android:text="1" android:textColor="#ff444444" android:textSize="30sp" /> <TextView android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginRight="1dp" android:layout_weight="1" android:background="#FFFFFF" android:gravity="center" android:padding="8dp" android:text="2" android:textColor="#ff444444" android:textSize="30sp" /> <TextView android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:background="#FFFFFF" android:gravity="center" android:padding="8dp" android:text="3" android:textColor="#ff444444" android:textSize="30sp" /> LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="1dp"> <TextView android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginRight="1dp" android:layout_weight="1" android:background="#FFFFFF" android:gravity="center" android:padding="8dp" android:text="4" android:textColor="#ff444444" android:textSize="30sp" /> <TextView android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginRight="1dp" android:layout_weight="1" android:background="#FFFFFF" android:gravity="center" android:padding="8dp" android:text="5" android:textColor="#ff444444" android:textSize="30sp" /> <TextView android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:background="#FFFFFF" android:gravity="center" android:padding="8dp" android:text="6" android:textColor="#ff444444" android:textSize="30sp" /> LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="1dp"> <TextView android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginRight="1dp" android:layout_weight="1" android:background="#FFFFFF" android:gravity="center" android:padding="8dp" android:text="7" android:textColor="#ff444444" android:textSize="30sp" /> <TextView android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginRight="1dp" android:layout_weight="1" android:background="#FFFFFF" android:gravity="center" android:padding="8dp" android:text="8" android:textColor="#ff444444" android:textSize="30sp" /> <TextView android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:background="#FFFFFF" android:gravity="center" android:padding="8dp" android:text="9" android:textColor="#ff444444" android:textSize="30sp" /> LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="1dp" android:orientation="horizontal"> <TextView android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginRight="1dp" android:layout_weight="1" android:gravity="center" android:padding="8dp" android:textColor="#ff444444" android:textSize="30sp" /> <TextView android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginRight="1dp" android:layout_weight="1" android:background="#FFFFFF" android:gravity="center" android:padding="8dp" android:text="0" android:textColor="#ff444444" android:textSize="30sp" /> <TextView android:layout_width="0dp" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:layout_weight="1" android:gravity="center" android:padding="8dp" android:text="删除" android:textColor="#ff444444" /> LinearLayout>LinearLayout>
pay_password_dialog_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" xmlns:ver="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#FFFFFFFF" android:orientation="vertical"> <TextView android:id="@+id/tv_title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:paddingTop="18dp" android:paddingBottom="18dp" android:text="请输入支付密码" android:textColor="#ff252525" android:textSize="16sp" /> <TextView android:layout_width="match_parent" android:layout_height="1dp" android:background="#FFEEEEEE" /> <com.example.paybox.PasswordEditText android:id="@+id/password_et" android:layout_width="match_parent" android:layout_height="47dp" android:layout_marginTop="20dp" android:layout_marginStart="15dp" android:layout_marginEnd="15dp" android:layout_marginBottom="40dp" android:background="@null" /> <com.example.paybox.CustomerKeyboard android:id="@+id/custom_key_board" android:layout_width="match_parent" android:layout_height="wrap_content" />LinearLayout>
到这里就结束啦。往期精彩回顾:
Android指纹识别详解
Android使用SurfaceView实现花瓣飘落效果
Android实现清理缓存功能
换肤框架Android-skin-support的使用
Android实现商城购物车功能