首先上张效果图看看
device-2018-07-10-112505.gif
[图片上传中...((JQE1LR~C6[W9_R810HC4PJ.png-650e6a-1531195051613-0)]
ps.png
看这样一张图 我们首先需要绘制这样一个View
1. 绘制外围Rect 2. 绘制分割线 3. 绘制圆点密码
大家看到边框、分割线、圆点密码的颜色、大小、都是通过自定义属性而获得。
自定义属性
<?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="dimension"/> <!--背景边框的颜色--> <attr name="bgColor" format="color"/> <!--背景边框的大小--> <attr name="bgSize" format="dimension"/> <!--背景边框的圆角大小--> <attr name="bgCorner" format="dimension"/> </declare-styleable></resources>
自定义密码输入框的View
public class PasswordEditText extends AppCompatEditText {// 画笔-->绘制背景框private Paint mRectPaint;// 画笔--> 绘制密码private Paint mPasswordPaint;// 一个密码所占的宽度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 = Color.parseColor("#000000");// 密码圆点的半径大小private int mPasswordRadius = 4;//密码输入完毕需要一个接口回调出去private PasswordFullListener mPasswordFullListener;public PasswordEditText(Context context) { this(context, null); }public PasswordEditText(Context context, AttributeSet attrs) { super(context, attrs); initAttributeSet(context, attrs); //不显示光标 setCursorVisible(false); //不弹出系统软键盘 setInputType(InputType.TYPE_NULL); setBackground(null); initPaint(); }/** * 初始化属性 */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, mPasswordColor); array.recycle(); }/** * 初始化画笔 */private void initPaint() { //初始化绘制边框的画笔 mRectPaint = new Paint(); mRectPaint.setAntiAlias(true); mRectPaint.setDither(true); mRectPaint.setColor(mBgColor); //初始化密码远点的画笔 mPasswordPaint = new Paint(); mPasswordPaint.setAntiAlias(true); mPasswordPaint.setDither(true); mPasswordPaint.setColor(mPasswordColor); } @Overrideprotected void onDraw(Canvas canvas) { //不需要调用super.onDraw(canvas); 为什么不需要呢?你去调用试试看,就明白为什么了 //super.onDraw(canvas); //一个密码的宽度 mPasswordItemWidth = (getWidth() - mBgSize * 2 - (mPasswordNumber - 1) * mDivisionLineSize) / mPasswordNumber; drawRect(canvas); drawDivisionLine(canvas); drawPassword(canvas); if (mPasswordFullListener != null) { //获取输入的密码 String password = getText().toString().trim(); if (password.length() == mPasswordNumber) { mPasswordFullListener.passwordFull(password); } } }/** * 绘制背景框 * * @param canvas 画布 */private void drawRect(Canvas canvas) { //矩形 RectF rect = new RectF(mBgSize, mBgSize, getWidth() - mBgSize, getHeight() - mBgSize); mRectPaint.setStrokeWidth(mBgSize); //画空心 mRectPaint.setStyle(Paint.Style.STROKE); if (mBgCorner == 0) { canvas.drawRect(rect, mRectPaint); } else { canvas.drawRoundRect(rect, mBgCorner, mBgCorner, mRectPaint); } }/** * 绘制分割线 * * @param canvas 画布 */private void drawDivisionLine(Canvas canvas) { mRectPaint.setStrokeWidth(mDivisionLineSize); for (int i = 0; i < mPasswordNumber - 1; i++) { int startX = mBgSize + (i + 1) * mPasswordItemWidth + i * mDivisionLineSize; int startY = 0; int endX = startX; int endY = getHeight() - mBgSize; canvas.drawLine(startX, startY, endX, endY, mRectPaint); } }/** * 绘制圆点密码 * * @param canvas 画布 */private void drawPassword(Canvas canvas) { //圆点密码是实行的 mPasswordPaint.setStyle(Paint.Style.FILL); int length = getText().toString().length(); for (int i = 0; i < length; i++) { int cx = mBgSize + i * mDivisionLineSize + i * mPasswordItemWidth + mPasswordItemWidth / 2; int cy = getHeight() / 2; canvas.drawCircle(cx, cy, mPasswordRadius, mPasswordPaint); } }public void addPassword(String number) { if (TextUtils.isEmpty(number)) { return; } //把密码取取出来 String password = getText().toString().trim(); if (password.length() <= mPasswordNumber) { //密码叠加 password += number; setText(password); } }/** * 删除密码 */public void deletePassword() { String password = getText().toString().trim(); if (TextUtils.isEmpty(password)) { return; } password = password.substring(0, password.length() - 1); setText(password); }private int dip2px(int dip) { return ( int ) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dip, getResources().getDisplayMetrics()); }/** * 设置一个密码输入完毕的监听器 * * @param passwordFullListener Listener */public void setPasswordFullListener(PasswordFullListener passwordFullListener) { this.mPasswordFullListener = passwordFullListener; }public interface PasswordFullListener { void passwordFull(String password); } }
最主要的是去求出每个密码的宽度、分割线的坐标位置(float startX, float startY, float stopX, float stopY)和原点密码的(cx,cy);
key.png
在看这样一个数字键盘,是写一个这样的布局,很简单的。关键是怎么给每一个View设置一个点击事件。每一个View 我们都去绑定一个Id,然后设置onClick事件吗?这样做,那是不可能的。具体这样做,看代码
/** * 给每一个自定义数字键盘上的View 设置点击事件 * * @param view */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设置setOnClickListener View childView = (( ViewGroup ) view).getChildAt(i); setItemClickListener(childView); } } else { view.setOnClickListener(this); } }
说下思路,键盘的整体布局是个LineaLayout,每一行布局是一个LineaLayout,然后每个LineaLayout会有三个子TextView。我们去递归下,这样每次循环都去拿View,不是ViewGroup,那就是View。
源码地址:https://github.com/StevenYan88/PayPasswordEditText
点击查看更多内容
1人点赞
评论
共同学习,写下你的评论
评论加载中...
作者其他优质文章
正在加载中
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦