Android开发——本地验证码的简易实现

0.  前言  

验证码无处不在。有人问我,你知道达芬奇password以下是什么吗,对。答案就是达芬奇验证码。

验证码一个最基本的作用就是防止恶意暴力破解登录,防止不间断的登录尝试,事实上能够在server端对该终端进行登录间隔检測。假设间隔太短能够展示拒绝的姿态。可是还是本地验证码作用更加实在。能够减轻server端的压力。这篇将使用自己定义View来实现一个例如以下效果的简易本地验证码。算是对自己定义View知识的复习吧。



1.  布局结构  

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:myattribute="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <com.calvin.verification_code.MyView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:padding="10dp"
        myattribute:text="0 0 0 0 "
        myattribute:textcolor="#000"
        myattribute:textsize="40sp"
        android:id="@+id/myView" />

    <EditText
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:inputType="number"
        android:hint="刷新后输入"
        android:layout_below="@+id/myView"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="20dp"
        android:id="@+id/editText" />

    <Button
        android:text="确认"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBottom="@+id/editText"
        android:layout_alignParentEnd="true"
        android:layout_marginEnd="10dp"
        android:id="@+id/button" />
</RelativeLayout>

在自己定义控件MyView中使用了自己定义属性。面试的时候偶尔也会被问到,事实上并不难。这里使用文字内容、颜色和字号三个自己定义属性。命名空间别忘了加。

自己定义属性声明仅仅须要在values文件夹下声明一个xml文件就可以。文件名称字不重要。重要的是这个name属性,由于我们会在自己定义控件类中通过R.styleable.MyView来找到这个自己定义属性声明信息。

<?

xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="MyView"> <attr name="text" format="string"/> <attr name="textcolor" format="color"/> <attr name="textsize" format="dimension"/> </declare-styleable> </resources>


2.  自己定义View

看一下这个类的构造函数:

public MyView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MyView);
        for (int i = 0; i < a.getIndexCount(); i++) {
            int attr = a.getIndex(i);
            switch (attr) {
                case R.styleable.MyView_text:
                    mText = a.getString(attr);
                    break;
                case R.styleable.MyView_textcolor:
                    //二參为默认颜色
                    mTextColor = a.getColor(attr, Color.BLACK);
                    break;
                case R.styleable.MyView_textsize:
                    // 默认字体大小为16sp,TypeValue把sp转化为px
                    mTextSize = a.getDimensionPixelSize(attr,
                            (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,
                                    16, getResources().getDisplayMetrics()));
                    break;
            }
        }
        a.recycle();

        mPaint = new Paint();
        mPaint.setTextSize(mTextSize);
        mBound = new Rect();
        //获得绘制文本的宽和高
        mPaint.getTextBounds(mText, 0, mText.length(), mBound);

        this.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                //生成一个随机的四位数字,并发送一个自己定义广播
                mText = randomText();
                postInvalidate();
            }

        });
    }

核心代码就是解析自己定义属性,并初始化一个画笔。并把解析出来的字体大小设置给画笔,设计点击时间,使其被点击后又一次随机产生四位数字验证码,并使用postInvalidate()刷新界面。最后使用mBound记录这个四位数文本的宽高。

 

2.  自己定义View类中的其它细节

@Override    
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int width = 0;
        int height = 0;
        int specMode = MeasureSpec.getMode(widthMeasureSpec);
        int specSize = MeasureSpec.getSize(widthMeasureSpec);
        switch (specMode) {
            case MeasureSpec.EXACTLY:
                width = getPaddingLeft() + getPaddingRight() + specSize;
                break;
            case MeasureSpec.AT_MOST:
                width = getPaddingLeft() + getPaddingRight() + mBound.width();
                break;
        }
        //相同逻辑处理高
        setMeasuredDimension(width, height);
}

    @Override
    protected void onDraw(Canvas canvas) {
        mPaint.setColor(Color.YELLOW);
        canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), mPaint);

        mPaint.setColor(mTextColor);
        canvas.drawText(mText, getWidth() / 2 - mBound.width() / 2, getHeight() / 2 + mBound.height() / 2, mPaint);
        Random random = new Random();
        for(int i = 0; i <= 3; i++){
            int temp = random.nextInt(colors.length);
            mPaint.setColor(colors[temp]);
            mPaint.setStrokeWidth(3);
            canvas.drawLine(randomStartWidth(),randomStartHeight(),randomEndWidth(),randomEndHeight(),mPaint);
        }
    }

事实上主要还是measuredraw的过程了。

onMeasure()方法中最重要的逻辑应该就是处理MeasureSpec.AT_MOST的这样的情况了。这时候前面的mBound.width()就起作用了。还有就是无论何种測量模式,都手动处理了padding的情况。

onDraw()方法中首先绘制了一个黄色矩形作为自己定义View的背景,接着依据自己定义属性中的文字内容和颜色绘制四位数字,最后绘制四条噪声直线。颜色随机,而且起始位置和结束位置也是随机产生的。

 

3.  实时改变维护的正确验证码

为了验证用户输入的验证码的正确性,须要在MainActivity中维护一个变量。在用户点击自己定义View刷新验证码时,能够实时改变这个变量的值。这里使用自己定义广播实现。在生成一个随机的四位数字,发送一个自己定义广播。

Intent intent = new Intent();
intent.setAction("com.seu_calvin.update");
intent.putExtra("data", sb.toString());
getContext().sendBroadcast(intent);

接着在MainActivity注冊一个广播接收者就可以取得此时的验证码信息,在用户点击确定按钮后在拿到EditText中的值与其进行对照就可以。

这个逻辑还是比較简单的。

笔者水平有限,假设有问题或者错误请多留言交流。

转载请注明出处:http://blog.csdn.net/seu_calvin/article/details/70156547

原文地址:https://www.cnblogs.com/yjbjingcha/p/7305069.html