Android从零开搞系列:自定义View(16)自定义验证码输入框效果

转载请注意:http://blog.csdn.net/wjzj000/article/details/75007555

本菜开源的一个自己写的Demo,希望能给Androider们有所帮助,水平有限,见谅见谅…
https://github.com/zhiaixinyang/PersonalCollect (拆解GitHub上的优秀框架于一体,全部拆离不含任何额外的库导入)
https://github.com/zhiaixinyang/MyFirstApp(Retrofit+RxJava+MVP)


写在前面

本篇博客记录了我的第一个开源库相关内容。效果如下:

这里写图片描述

源码地址:https://github.com/zhiaixinyang/VerifyCodeView
用法很简单:

compile 'verifycode.com.verifycode:verifycodeview:1.0'

想要出现上图的效果,这么做即可。(具体的属性的注释可以查看GitHub

    <verifycode.com.verifycode.VerifyCodeView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:verifyCodeLength="5"
        app:verifyCodeMode="1"
        app:verifyCodeTextSize="24sp"
        app:verifyCodeTextColor="@color/colorAccent"
         />

开始解读源码

接下来就让我们进行对源码来一遍翻云覆雨…

思路:

这里我的思路是直接继承View,一切全部交由自己去绘制。(当然也可以继承自TextView)
如果单看效果,实现起来比较的简单:确定好每个验证码所要显示的位置,然后画边框,绘制数字就ok了。思路我们大体清楚了,接下来让我们一同走进广阔无垠的亚欧大陆。冰雪消融,万物复苏,空气中充满着荷尔蒙的气味,又到了看代码的时间了!

第一步:

最开始肯定是,编写自定义属性:

    <declare-styleable name="VerifyCodeView">
        <attr name="verifyCodeLength" format="integer" />
        <attr name="verifyCodeMode" format="integer" />
        <attr name="verifyCodePadding" format="dimension" />
        <attr name="verifyCodeBorderColor" format="color" />
        <attr name="verifyCodeBorderWidth" format="dimension" />
        <attr name="verifyCodeTextSize" format="dimension" />
        <attr name="verifyCodeCursorFlashTime" format="integer" />
        <attr name="isVerifyCodeCursorEnable" format="boolean" />
        <attr name="verifyCodeCursorColor" format="color" />
        <attr name="verifyCodeTextColor" format="color" />
    </declare-styleable>
TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.VerifyCodeView);

verifyCodeMode =typedArray.getInteger(R.styleable.VerifyCodeView_verifyCodeMode,0);
verifyCodeLength = typedArray.getInteger(R.styleable.VerifyCodeView_verifyCodeLength, 4);
isCursorEnable = typedArray.getBoolean(R.styleable.VerifyCodeView_isVerifyCodeCursorEnable, true);
cursorFlashTime = typedArray.getInteger(R.styleable.VerifyCodeView_verifyCodeCursorFlashTime, 500);
borderWidth = typedArray.getDimensionPixelSize(R.styleable.VerifyCodeView_verifyCodeBorderWidth, dp2px(3));
//默认的所有颜色都是黑色的
borderColor = typedArray.getColor(R.styleable.VerifyCodeView_verifyCodeBorderColor, Color.BLACK);
cursorColor = typedArray.getColor(R.styleable.VerifyCodeView_verifyCodeCursorColor, Color.BLACK);
textColor = typedArray.getColor(R.styleable.VerifyCodeView_verifyCodeTextColor,Color.BLACK);
            textSize=typedArray.getDimensionPixelSize(R.styleable.VerifyCodeView_verifyCodeTextSize,sp2px(16));
verifyCodePadding = typedArray.getDimensionPixelSize(R.styleable.VerifyCodeView_verifyCodePadding, dp2px(10));
typedArray.recycle();

这个过程就不多做累述了,获取xml中的自定义属性,赋予初始值,都是些套路性的代码。


第二步:

这里我们需要进行输入验证码,而且我们使用的是继承View,因此我们要进行监听输入框。这里我们实现了一个内部类,然后初始化的时候调用setOnKeyListener(内部类);

    class VerifyCodeKeyListener implements OnKeyListener {
        @Override
        public boolean onKey(View v, int keyCode, KeyEvent event) {
            int action = event.getAction();
            if (action == KeyEvent.ACTION_DOWN) {
                //删除操作
                if (keyCode == KeyEvent.KEYCODE_DEL) {
                    if (TextUtils.isEmpty(verifyCode[0])) {
                        return true;
                    }
                    String deleteText = delete();
                    if (verifyCodeListener != null && !TextUtils.isEmpty(deleteText)) {
                        //这里是对外提供的回调,如果使用这实现了回调可以对应进行处理
                        verifyCodeListener.verifyCodeChange(deleteText);
                    }
                    postInvalidate();
                    return true;
                }

                if (keyCode >= KeyEvent.KEYCODE_0 && keyCode <= KeyEvent.KEYCODE_9) {
                    /**
                     * 只支持数字
                     */
                    if (isInputComplete) {
                        return true;
                    }
                    String addText = add((keyCode - 7) + "");
                    if (verifyCodeListener != null && !TextUtils.isEmpty(addText)) {
                        //这里是对外提供的回调,如果使用这实现了回调可以对应进行处理
                        verifyCodeListener.verifyCodeChange(addText);
                    }
                    postInvalidate();
                    return true;
                }

                if (keyCode == KeyEvent.KEYCODE_ENTER) {
                    /**
                     * 确认键
                     */
                    if (verifyCodeListener != null) {
                        //这里是对外提供的回调,如果使用这实现了回调可以对应进行处理
                        verifyCodeListener.keyEnterPress(getVerifyCode(), isInputComplete);
                    }
                    return true;
                }
            }
            return false;
        }
    }

回调的代码:


    /**
     * 验证码监听者回调
     */
    public interface VerifyCodeListener {
        /**
         * 输入/删除监听
         *
         * @param changeText  输入/删除的字符
         */
        void verifyCodeChange(String changeText);

        /**
         * 输入完成
         */
        void verifyCodeComplete();

        /**
         * 确认键后的回调
         *
         * @param verifyCode   验证码
         * @param isComplete 是否达到要求位数
         */
        void keyEnterPress(String verifyCode, boolean isComplete);

    }

第三步:

第三部便是我们的重头戏,计算位置,绘制内容。
这里主要是onDraw()中的几个方法

    /**
     * 绘制光标
     */
    private void drawCursor(Canvas canvas, Paint paint) {

        //光标未显示 && 开启光标 && 输入位数未满 && 获得焦点
        if (!isCursorShowing && isCursorEnable && !isInputComplete && hasFocus()) {
            /**
             * 起始点x点 = paddingLeft + 一个验证码框大小 / 2 + (一个验证码框大小 + 验证码框间距) * 光标下标
             * 起始点y点 = paddingTop + (一个验证码框大小 - 光标大小) / 2
             * 终止点x点 = 起始点x
             * 终止点y点 = 起始点y + 光标高度
             */
            canvas.drawLine((getPaddingLeft() + textSize / 2) + (textSize + verifyCodePadding) * cursorPosition,
                    getPaddingTop() + (textSize - cursorHeight) / 2,
                    (getPaddingLeft() + textSize / 2) + (textSize + verifyCodePadding) * cursorPosition,
                    getPaddingTop() + (textSize + cursorHeight) / 2,
                    paint);
        }
    }

    /**
     * 下划线式的验证码外框
     */
    private void drawUnderLine(Canvas canvas, Paint paint) {

        for (int i = 0; i < verifyCodeLength; i++) {
            /**
             * 根据验证码位数for循环绘制下划线
             * 起始点x点 = paddingLeft + (一个验证码框大小 + 验证码框边距) * i 
             * 起始点y点 = paddingTop + 一个验证码框大小
             * 终止点x点 = 起始点x点 + 一个验证码框大小 
             * 终止点y点 = 起始点y点
             */
            canvas.drawLine(getPaddingLeft() + (textSize + verifyCodePadding) * i, getPaddingTop() + textSize,
                    getPaddingLeft() + (textSize + verifyCodePadding) * i + textSize, getPaddingTop() + textSize,
                    paint);
        }
    }

    /**
     * 圆形的验证码外框
     */
    private void drawCircle(Canvas canvas, Paint paint) {
        paint.setColor(borderColor);
        paint.setStrokeWidth(dp2px(2));
        paint.setStyle(Paint.Style.STROKE);
        for (int i = 0; i < verifyCodeLength; i++) {
            float startX = getPaddingLeft() + (textSize + verifyCodePadding) * i;
            float startY = getPaddingTop();
            float stopX = getPaddingLeft() + (textSize + verifyCodePadding) * i + textSize;
            float stopY = getPaddingTop() + textSize;
            canvas.drawCircle((startX+stopX)/2,(startY+stopY)/2,dp2px(20), paint);
        }
    }

尾声

整体思路就是如此,比较的简单。如果有需要的话可以移步GitHub查看源码。

最后希望各位看官可以star我的GitHub,三叩九拜,满地打滚求star:
https://github.com/zhiaixinyang/PersonalCollect
https://github.com/zhiaixinyang/MyFirstApp

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值