仿支付宝密码输入框
2019-10-21 本文已影响0人
migill

1、定义6位密码输入View,PasswordEditText.java
思路:要绘制边框矩形,绘制分割线,绘制圆点。绘制圆的数目要与字符串的长度有关,添加或者删除都要修改字符串,输入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">@null</item>
<!--这个说明提示框是否是浮动-->
<item name="android:windowIsFloating">true</item>
<!--是否有遮盖-->
<item name="android:windowContentOverlay">@null</item>
<item name="android:windowAnimationStyle">@android:style/Animation.Dialog</item>
<item name="android:windowSoftInputMode">stateUnspecified|adjustPan</item>
</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>