为了账号安全,请及时绑定邮箱和手机立即绑定

Android-打造一个属于自己的支付密码输入框

标签:
Android

首先上张效果图看看

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人点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
移动开发工程师
手记
粉丝
1.4万
获赞与收藏
118

关注作者,订阅最新文章

阅读免费教程

感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消