美文网首页
Android 手机内部验证码

Android 手机内部验证码

作者: 那个唐僧 | 来源:发表于2017-03-03 14:00 被阅读97次

    此为手机内部验证码,不是本人自己创作,因为时间紧张,拉别人的demo.在此感谢那位兄弟..那位兄弟注释写的很详细,能够一目了然.所以就不用重复造轮子了.
    gif图片没时间截取了,按照此代码复用即可实现.

    首先自定义属性

        <declare-styleable name="VerifyCode">
            <attr name="codeTextSize" format="dimension"/>
            <attr name="codeBackground" format="color"/>
            <attr name="codeLength" format="integer"/>
            <attr name="isContainChar" format="boolean"/>
            <attr name="pointNum" format="integer"/>
            <attr name="linNum" format="integer"/>
        </declare-styleable>
    

    其次布局

    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:VerifyCode="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context="com.scc.yanzhengma.MainActivity">
    
        <com.scc.yanzhengma.VerifyCode
            android:id="@+id/VerifyCode"
            android:layout_width="100dp"
            android:layout_height="50dp"
            VerifyCode:codeLength="4"
            VerifyCode:codeTextSize="18sp"
            VerifyCode:isContainChar="false"
            VerifyCode:linNum="10"
            VerifyCode:pointNum="10"
            />
    
        <Button
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:onClick="click"
            android:text="点击刷新验证码"
            android:textSize="25sp"
            />
    
        <EditText
            android:id="@+id/et_code"
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:hint="输入验证码"
            android:textSize="25sp"
            />
        <Button
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:onClick="check"
            android:text="点击验证"
            android:textSize="25sp"
            />
    </LinearLayout>
    

    再次自定义View类

    package com.scc.yanzhengma;
    
    import android.content.Context;
    import android.content.res.TypedArray;
    import android.graphics.Bitmap;
    import android.graphics.Canvas;
    import android.graphics.Color;
    import android.graphics.Paint;
    import android.graphics.PointF;
    import android.graphics.Rect;
    import android.util.AttributeSet;
    import android.util.TypedValue;
    import android.view.MotionEvent;
    import android.view.View;
    
    import java.util.Random;
    
    /**
     * 类描述:自定义验证码
     * 创建者:lb
     */
    
    public class VerifyCode extends View {
    
        private String mCodeText;//文本内容
        private int mCodeTextSize;//文本大小
        private int mCodeLength;//验证码长度
        private int mCodeBackground;//背景色
        private boolean isContainChar;//验证码是否包含字母
        private int mPointNum;//干扰点数
        private int mLineNum;//干扰线数
    
        private Paint mPaint;//画笔
        private Rect mBound;//绘制范围
        private Bitmap bitmap;//验证码图片
    
        private static Random mRandom = new Random();
        private static int mWidth;//控件的宽度
        private static int mHeight;//控件的高度
    
    
        public VerifyCode(Context context) {
            super(context);
        }
    
        public VerifyCode(Context context, AttributeSet attrs) {
            super(context, attrs);
            initAttrValues(context,attrs);
            initData();
        }
    
        /**
         * 初始化属性集合
         * @param context
         * @param attrs
         */
        private void initAttrValues(Context context, AttributeSet attrs){
            // //获取在AttributeSet中定义的 VerifyCode 中声明的属性的集合
            TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.VerifyCode);
            //获取TypeArray的长度
            int count=typedArray.getIndexCount();
            for (int i=0;i<count;i++){
                //获取此项属性的ID
                int index=typedArray.getIndex(i);
                switch (index){
                    case R.styleable.VerifyCode_codeTextSize:
                        // 默认设置为16sp,TypeValue类 px转sp 一个转换类
                        mCodeTextSize =typedArray.getDimensionPixelSize(index,(int) TypedValue.applyDimension(
                                TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics()));
                        break;
                    case R.styleable.VerifyCode_codeBackground:
                        mCodeBackground=typedArray.getColor(index,Color.WHITE);
                        break;
                    case R.styleable.VerifyCode_codeLength:
                        mCodeLength=typedArray.getInteger(index,4);
                        break;
                    case R.styleable.VerifyCode_isContainChar:
                        isContainChar=typedArray.getBoolean(index,false);
                        break;
                    case R.styleable.VerifyCode_pointNum:
                        mPointNum=typedArray.getInteger(index,100);
                        break;
                    case R.styleable.VerifyCode_linNum:
                        mLineNum=typedArray.getInteger(index,3);
                        break;
                }
            }
            //Recycles the TypedArray, to be re-used by a later caller
            //官方解释:回收TypedArray 以便后面的使用者重用
            typedArray.recycle();
        }
    
        /**
         * 初始化数据
         */
        private void initData(){
            mCodeText=getValidationCode(mCodeLength,isContainChar);
            mPaint=new Paint();
            mPaint.setAntiAlias(true);
            mBound=new Rect();
            //计算文字所在矩形,可以得到宽高
            mPaint.getTextBounds(mCodeText,0, mCodeText.length(),mBound);
    
        }
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            //获取控件宽高的显示模式
            int widthMode=MeasureSpec.getMode(widthMeasureSpec);
            int heightMode=MeasureSpec.getMode(heightMeasureSpec);
            //获取宽高的尺寸值  固定值的宽度
            int widthSize=MeasureSpec.getSize(widthMeasureSpec);
            int heightSize=MeasureSpec.getSize(heightMeasureSpec);
            //设置宽高默认为建议的最小宽高
            int width= getDefaultSize(getSuggestedMinimumWidth(),widthMeasureSpec) ;
            int height=getDefaultSize(getSuggestedMinimumHeight(),heightMeasureSpec);
    
    //        MeasureSpec父布局传递给后代的布局要求 包含 确定大小和三种模式
    //        EXACTLY:一般是设置了明确的值或者是MATCH_PARENT
    //        AT_MOST:表示子布局限制在一个最大值内,一般为WARP_CONTENT
    //        UNSPECIFIED:表示子布局想要多大就多大,很少使用
            if (widthMode==MeasureSpec.EXACTLY){
                width=widthSize;
            }else{
                mPaint.setTextSize(mCodeTextSize);
                mPaint.getTextBounds(mCodeText,0,mCodeText.length(),mBound);
                float textWidth=mBound.width();
                int tempWidth=(int)(getPaddingLeft()+textWidth+getPaddingRight());
                width=tempWidth;
            }
            if (heightMode == MeasureSpec.EXACTLY)
            {
                height = heightSize;
            } else
            {
                mPaint.setTextSize(mCodeTextSize);
                mPaint.getTextBounds(mCodeText, 0, mCodeText.length(), mBound);
                float textHeight = mBound.height();
                int tempHeight = (int) (getPaddingTop() + textHeight + getPaddingBottom());
                height = tempHeight;
            }
            //设置测量的宽高
            setMeasuredDimension(width,height);
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
    
            mWidth=getWidth();
            mHeight=getHeight();
    
            if (bitmap==null){
                bitmap=createBitmapValidate();
            }
            canvas.drawBitmap(bitmap,0,0,mPaint);
    
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            switch (event.getAction()){
                case MotionEvent.ACTION_DOWN:
                    refresh();
                    break;
            }
            return super.onTouchEvent(event);
        }
    
        /**
         * 创建图片验证码
         * @return
         */
        private Bitmap createBitmapValidate(){
            if(bitmap != null && !bitmap.isRecycled()){
                //回收并且置为null
                bitmap.recycle();
                bitmap = null;
            }
            //创建图片
            Bitmap sourceBitmap=Bitmap.createBitmap(mWidth,mHeight, Bitmap.Config.ARGB_8888);
            //创建画布
            Canvas canvas=new Canvas(sourceBitmap);
            //画上背景颜色
            canvas.drawColor(mCodeBackground);
            //初始化文字画笔
            mPaint.setStrokeWidth(3f);
            mPaint.setTextSize(mCodeTextSize);
            //测量验证码字符串显示的宽度值
            float textWidth=mPaint.measureText(mCodeText);
            //画上验证码
            int length = mCodeText.length();
            //计算一个字符的所占位置
            float charLength = textWidth / length;
            for (int i = 1; i <= length; i++) {
                int offsetDegree = mRandom.nextInt(15);
                //这里只会产生0和1,如果是1那么正旋转正角度,否则旋转负角度
                offsetDegree = mRandom.nextInt(2) == 1 ? offsetDegree : -offsetDegree;
                //用来保存Canvas的状态。save之后,可以调用Canvas的平移、放缩、旋转、错切、裁剪等操作。
                canvas.save();
                //设置旋转
                canvas.rotate(offsetDegree, mWidth / 2, mHeight / 2);
                //给画笔设置随机颜色
                mPaint.setARGB(255, mRandom.nextInt(200) + 20, mRandom.nextInt(200) + 20,
                        mRandom.nextInt(200) + 20);
                //设置字体的绘制位置
                canvas.drawText(String.valueOf(mCodeText.charAt(i - 1)), (i - 1) * charLength+5,
                        mHeight * 4 / 5f, mPaint);
                //用来恢复Canvas之前保存的状态。防止save后对Canvas执行的操作对后续的绘制有影响。
                canvas.restore();
            }
    
            //重新设置画笔
            mPaint.setARGB(255, mRandom.nextInt(200) + 20, mRandom.nextInt(200) + 20,
                    mRandom.nextInt(200) + 20);
            mPaint.setStrokeWidth(1);
            //产生干扰效果1 -- 干扰点
            for (int i = 0; i < mPointNum; i++) {
                drawPoint(canvas, mPaint);
            }
            //生成干扰效果2 -- 干扰线
            for (int i = 0; i < mLineNum; i++) {
                drawLine(canvas, mPaint);
            }
            return sourceBitmap;
        }
    
        /**
         * 生成干扰点
         */
        private static void drawPoint(Canvas canvas, Paint paint) {
            PointF pointF = new PointF(mRandom.nextInt(mWidth) + 10, mRandom.nextInt(mHeight) + 10);
            canvas.drawPoint(pointF.x, pointF.y, paint);
        }
    
        /**
         * 生成干扰线
         */
        private static void drawLine(Canvas canvas, Paint paint) {
            int startX = mRandom.nextInt(mWidth);
            int startY = mRandom.nextInt(mHeight);
            int endX = mRandom.nextInt(mWidth);
            int endY = mRandom.nextInt(mHeight);
            canvas.drawLine(startX, startY, endX, endY, paint);
        }
    
        /**
         * 获取验证码
         *
         * @param length 生成随机数的长度
         * @param contains 是否包含字符串
         * @return
         */
        public String getValidationCode(int length,boolean contains) {
            String val = "";
            Random random = new Random();
    
            for (int i = 0; i < length; i++) {
                if (contains){
                    //字母或数字
                    String code = random.nextInt(2) % 2 == 0 ? "char" : "num";
                    //字符串
                    if ("char".equalsIgnoreCase(code)) {
                        //大写或小写字母
                        int choice = random.nextInt(2) % 2 == 0 ? 65 : 97;
                        val += (char) (choice + random.nextInt(26));
                    } else if ("num".equalsIgnoreCase(code)) {
                        val += String.valueOf(random.nextInt(10));
                    }
                }else{
                    val += String.valueOf(random.nextInt(10));
                }
    
            }
            return val;
        }
    
        /**
         *判断验证码是否一致 忽略大小写
         */
        public Boolean isEqualsIgnoreCase(String CodeString) {
            return mCodeText.equalsIgnoreCase(CodeString);
        }
    
        /**
         * 判断验证码是否一致 不忽略大小写
         */
        public Boolean isEquals(String CodeString) {
            return mCodeText.equals(CodeString);
        }
    
        /**
         * 提供外部调用的刷新方法
         */
        public void refresh(){
            mCodeText= getValidationCode(mCodeLength,isContainChar);
            bitmap = createBitmapValidate();
            invalidate();
        }
    }
    

    在MainActivity中调用

    public class MainActivity extends AppCompatActivity {
    
        private EditText code;
        private VerifyCode mVerifyCode;
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            code = (EditText) findViewById(R.id.et_code);
            mVerifyCode = (VerifyCode) findViewById(R.id.VerifyCode);
        }
    
        public void click(View view) {
            mVerifyCode.refresh();
        }
        public void check(View view) {
            String s = code.getText().toString();
            Boolean aBoolean = mVerifyCode.isEquals(s);
            if (aBoolean) {
                Toast.makeText(this, "OKOKOKOKOKOKOKOKOKOKOK", Toast.LENGTH_SHORT).show();
            } else {
                Toast.makeText(this, "NONONONONONONOONONONO", Toast.LENGTH_SHORT).show();
            }
        }
    }
    

    相关文章

      网友评论

          本文标题:Android 手机内部验证码

          本文链接:https://www.haomeiwen.com/subject/retrgttx.html