Android实用View系列-----仿微信支付宝等风格的支付密码输入框的实现

开始阅读本篇文章之前先来说一下使用场景吧,我们知道如今移动支付已经占据我们日常支付的90%的份额,以微信支付和支付宝支付为主,也越来越多的APP开始添加支付模块,不管使用哪种支付有一个步骤是少不了的,那就是输入支付密码(指纹支付再此就不做讨论了哦),所以今天来给大家带来一篇自定义支付密码输入框的设计和实现方式,同时记录自己工作中遇到的问题及解决办法。


github源码地址传送门


按照惯例我们先看看微信和支付宝支付密码输入框的样式吧
微信支付密码
支付宝支付密码
看到这样的效果相信很多开发者第一反应就是先网上搜一下看看有没有现成的(哈哈,我也不例外哦),因为这都是简单的一些view不涉及动画所以网上相关例子还是很多的,我这边总结了一下大致可以分为一下几类

1、通过布局的方式:

在布局里边放置6个EditView,在每个输入框中间再放置一个view用于设置中间分割线,每个EditVIew只允许输入一个字符,然后对每个进行监听,一个密码输入完之后让另一个EditView获取焦点,以此类推就可以大致实现图中的效果了(这样确实可以实现,实现起来也很简单,但是代码量不少,而且这种方式是不是显得逼格不够高或者没有逼格呐)

2、完全自定义view(继承View):

这个就稍微复杂一点,大致流程是,先监听触摸事件,按下时弹出键盘,然后对软键盘进行监听,获取每次点击键盘对应的字符串,然后在onDraw方法里边画6个圆,在绘制外边框,然后是中间的分割线。这里边有个问题就是每次都要对软键盘进行监听取值等一系列操作,加上Android机型众多整不好哪块软键盘就出问题了呐。(虽然有逼格,但是不实用哦)


欲步又止

3、继承自EditView实现自定义view:

大致流程和上一种差不多,不过我们不需要对软键盘进行处理了,少了很多繁琐及兼容性的操作,同时又不失逼格,哈哈。

看到以上三种实现方式想必你大概已经知道我们要使用哪种方式实现了,没错就是集成EditView的自定义view,这样我们还可以使用很多EditView的属性哦

开发前先整理一下实现步骤:

1、绘制外边框(可以是直角也可以是圆角,设计师要什么我们就给他什么)
2、绘制密码之间的分割线(竖线)

3、绘制实心圆代替输入的字符
4、对输入字符进行监听,便于扩展处理
5、实现一些常用的外部接口方法调用

具体实现

1、绘制外边框:
要想绘制边框我们首先要知道view的宽高,通过onSizeChanged方法去初始化宽高等数据,然后绘制圆角矩形(默认让他矩形显示直接传入圆角半径为0即可)

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        height = h;
        width = w;

        divideLineWStartX = w / maxCount;

        startX = w / maxCount / 2; //第一个圆心的x坐标
        startY = h / 2; //第一个圆心的y坐标

        bottomLineLength = w / (maxCount + 2);

        rectF.set(0, 0, width, height);

    }
RectF rectF = new RectF()
rectF.set(0, 0, width, height);

canvas.drawRoundRect(rectF, rectAngle, rectAngle, borderPaint);
2、绘制密码之间的分割线:
既然是分割线肯定是等均分的,假设我们的密码最大输入maxCount=6,那么我们只需画5个分割线就可以了,分割线坐标的计算
计算分割线的起点和终点的坐标
通过循环画出每个分割线
for (int i = 0; i < maxCount - 1; i++) {
            canvas.drawLine((i + 1) * divideLineWStartX,
                    0,
                    (i + 1) * divideLineWStartX,
                    height,
                    divideLinePaint);
        }

完成这一步我们先运行一下看看边框效果吧

模拟器上运行效果
3、绘制实心圆代替输入的字符:

这里需要监听EditView的输入,重写onTextChanged方法获取输入字符的长度,然后计算每个圆圆心的坐标位置

        //第一个圆心的x坐标
        startX = w / maxCount / 2;
        //第一个圆心的y坐标
        startY = h / 2;

    /**
     * 画密码实心圆
     *
     * @param canvas
     */
    private void drawPsdCircle(Canvas canvas) {
        for (int i = 0; i < textLength; i++) {
            canvas.drawCircle(startX + i * 2 * startX,
                    startY,
                    radius,
                    circlePaint);
        }
    }

写到这里的时候是不是感觉样式问题已经完成的差不多了,运行以来输入几个字符串一看,MD出问题了(看图说话)


Paste_Image.png

从图中可以看出是绘制了相应的实心圆,但是自带的底部线、光标、字符还在,要是拿这个去交差绝逼会被产品骂死。


产品的内心独白

出现这个问题肯定是代码的问题喽,我们根据问题去一个一个解决,首先给view设置一个透明的背景色,然后隐藏光标,再跑一下看看
        this.setBackgroundColor(Color.TRANSPARENT);
        this.setCursorVisible(false);
Paste_Image.png

这次底部的线和光标都见了,但是输入的字符还在,这又是什么问题???我们明明重写了onDraw方法,怎么还会出现原来的字符呐,等等。。。对啊,我们只是重写,他肯定还有自己的方法,我们只要把EditView内部重绘的方法干掉不就行了,想到这里喜出望外,拿跟辣条先压压惊,在ondraw方法中这样做

    @Override
    protected void onDraw(Canvas canvas) {
        //不删除的话会默认绘制输入的文字
       // super.onDraw(canvas);
    }

你没看错,就是这一行代码注释掉就ok,
至于是为什么你肯定知道,
不注释的话在我们重写之前他已经调用了内部方法
去绘制输入的字符了,
我们在重写后虽然我们的方法生效了,
但它的方法也生效了哦。

此时压抑不住内心的小激动赶紧运行起来看看(哈哈,完美解决问题)


Paste_Image.png

至此主要功能已经完成,剩下的需要去封装一些方法供外部调用,我这里已经封装几个方法,我们知道这样设置支付密码的页面一般有两个:一个设置密码,一个重新设置密码,按照正常的逻辑我们去监听这个密码输入框,输入密码之后进行比较看是否相等就完事了,为了方便以后使用不要每次自己再去写一大堆监听方法,我们直接在内部封装好是不是对以后使用起来更方便一点呐

   /**
     * 密码比较监听
     */
    public interface onPasswordListener {
        void onDifference();
        void onEqual(String psd);
    }

    //使用者需要调用的方法
    public void setComparePassword(String comparePassword, onPasswordListener listener) {
        mComparePassword = comparePassword;
        mListener = listener;
    }

这里就直接上代码了,代码通俗易懂

    @Override
    protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) {
        super.onTextChanged(text, start, lengthBefore, lengthAfter);
        textLength = text.toString().length();

        if (mComparePassword != null && textLength == maxCount) {
            if (TextUtils.equals(mComparePassword, getPasswordString())) {
                mListener.onEqual(getPasswordString());
            } else {
                mListener.onDifference();
            }
        }
        invalidate();

    }

实际使用中我们这样设置(是不是瞬间感觉用的过程简单了很多)

        passwordInputView.setComparePassword("123456", new PayPsdInputView.onPasswordListener() {
            @Override
            public void onDifference() {
                // TODO: 2017/5/7   和上次输入的密码不一致  做相应的业务逻辑处理 
                Toast.makeText(MainActivity.this,"两次密码输入不同",Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onEqual(String psd) {
                // TODO: 2017/5/7 两次输入密码相同,那就去进行支付楼 
                Toast.makeText(MainActivity.this,"密码相同"+psd,Toast.LENGTH_SHORT).show();

            }
        });

文章到此本应该结束了,可是我们UI设计师给出的效果图不是这样子的,不按常理出牌(心中顿时飘过一万只草泥马)

草泥马

来看看我们的效果图


Paste_Image.png
大哥,算了算了,还是去给他实现一下吧

他不按常量出牌,不过这也是他们一贯的作风,既然他们要这样的效果那我们就去做喽,整个流程还是一样的,唯一的不同就是外边框和密码之间的分割线变成了底部间断的线,这肯定难不倒我们啦,不就是画六条线吗,每根线的起点终点坐标和上边圆心左边计算差不多,就不多描述了看代码最实在

    /**
     * 画底部显示的分割线
     *
     * @param canvas
     */
    private void drawBottomBorder(Canvas canvas) {

        for (int i = 0; i < maxCount; i++) {
            cX = startX + i * 2 * startX;
            canvas.drawLine(cX - bottomLineLength / 2,
                    height,
                    cX + bottomLineLength / 2,
                    height, bottomLinePaint);
        }
    }

项目至此完美收工,看看效果吧


MD你要的效果给你.png

最后总结

以上微信支付密码和我们这种现实效果我都封装在PayPsdInputView中了,可以根据需求切换不同的样式,


Paste_Image.png

如果以后还要其他的支付密码输入的样式的话同样会添加进来的,目的只有一个--------->下次开发省时省力。


两种样式供你选择

番外篇

我相信看到这里肯定有一部分小伙伴会说MDZZ,这不就是简单的画矩形、画圆、画线吗,有什么好写的,谁都会做。我想说的是你们说的没错,涉及的知识点是很简单,但是不要忘了,麻雀虽小五腑俱全,真正你去一行一行敲的时候你会发现有很多不曾注意过的问题都会浮出水面。只是单纯的会几个知识点其实没什么卵用,把所学知识点运用起来重组成一个功能模块的时候你才算真正的掌握。


来,老表,抽根烟,平复一下暴躁的心情

谨以此篇来记录自己项目中遇到的问题,献给需要类似功能的小伙伴们。如果你有好的建议欢迎评论指出,大家一起讨论、学习、进步!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 196,099评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,473评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,229评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,570评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,427评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,335评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,737评论 3 386
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,392评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,693评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,730评论 2 312
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,512评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,349评论 3 314
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,750评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,017评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,290评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,706评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,904评论 2 335

推荐阅读更多精彩内容