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

来源:互联网 发布:怎么看淘宝销售排行 编辑:程序博客网 时间:2024/06/04 07:17

转载请注意: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 0