自定义View学习之验证码
来源:互联网 发布:淘宝广告图片素材 编辑:程序博客网 时间:2024/06/16 02:51
自定义看了很多学习自定义的文章和各位大神的例子,综合起来写了一个验证码控件来练手。
如果你对自定义控件还不够了解那么你可以先看鸿洋的这篇文章来学习基本的知识。
先来一张效果图
- 1.先自定义两个属性用来设置view的字体大小和验证码的个数。
<declare-styleable name="VerificationCodeView"> <attr name="textSize" format="dimension" /> <attr name="textCount" format="integer" /> </declare-styleable>
- 2.在代码中获取属性值
public VerificationCodeView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.VerificationCodeView); mTextSize = a.getDimensionPixelSize(R.styleable.VerificationCodeView_textSize, (int) TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics())); mTextCount = a.getInt(R.styleable.VerificationCodeView_textCount, 4); a.recycle(); }
在这里着重说明一点:用完TypedArray一定要记得 调用recycle()
方法释放资源
- 3.测量
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); //测量宽度 int specMode = MeasureSpec.getMode(widthMeasureSpec); int specSize = MeasureSpec.getSize(widthMeasureSpec); if (specMode == MeasureSpec.EXACTLY) { mWidth = specSize; } else { if (specMode == MeasureSpec.AT_MOST) { mWidth = Math.min((int) (mTextWidth * 1.8f), specSize); } } //测量高度 specMode = MeasureSpec.getMode(heightMeasureSpec); specSize = MeasureSpec.getSize(heightMeasureSpec); if (specMode == MeasureSpec.EXACTLY) { mHeight = specSize; } else { if (specMode == MeasureSpec.AT_MOST) { mHeight = Math.min((int) (mTextWidth * 16f), specSize); } } setMeasuredDimension(mWidth, mHeight); }
- 4.初始化画笔
private void init() { mText = getCharAndNum(mTextCount); //初始化验证码画笔 mTextPaint = new Paint(); mTextPaint.setStrokeWidth(3); mTextPaint.setTextSize(mTextSize); //初始化干扰点画笔 mPointPaint = new Paint(); mPointPaint.setStrokeWidth(6); mPointPaint.setStrokeCap(Paint.Cap.ROUND); // 设置断点处为圆形 //初始化干扰线画笔 mPathPaint = new Paint(); mPathPaint.setStrokeWidth(5); mPathPaint.setColor(Color.GRAY); mPathPaint.setStyle(Paint.Style.STROKE); // 设置画笔为空心 mPathPaint.setStrokeCap(Paint.Cap.ROUND); // 设置断点处为圆形 // 取得验证码字符串显示的宽度值 mTextWidth = mTextPaint.measureText(mText); }
初始化最好不用放在onDraw()
方法里,在实际过程中onDraw()
方法可能会被多次调用。
- 5.初始化数据
private void initData() { mPoints.clear(); // 生成干扰点坐标 for (int i = 0; i < 150; i++) { PointF pointF = new PointF(mRandom.nextInt(mWidth) + 10, mRandom.nextInt(mHeight) + 10); mPoints.add(pointF); } mPaths.clear(); // 生成干扰线坐标 for (int i = 0; i < 2; i++) { Path path = new Path(); int startX = mRandom.nextInt(mWidth / 3) + 10; int startY = mRandom.nextInt(mHeight / 3) + 10; int endX = mRandom.nextInt(mWidth / 2) + mWidth / 2 - 10; int endY = mRandom.nextInt(mHeight / 2) + mHeight / 2 - 10; path.moveTo(startX, startY); path.quadTo(Math.abs(endX - startX) / 2, Math.abs(endY - startY) / 2, endX, endY); mPaths.add(path); } }
- 6.最后一步,绘制
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); setBackgroundColor(Color.GRAY); initData(); float charLength = mTextWidth / mTextCount; //绘制验证码 for (int i = 1; i <= mTextCount; i++) { int offsetDegree = mRandom.nextInt(15); // 这里只会产生0和1,如果是1那么正旋转正角度,否则旋转负角度 offsetDegree = mRandom.nextInt(2) == 1 ? offsetDegree : -offsetDegree; canvas.save(); //旋转画布 canvas.rotate(offsetDegree, mWidth / 2, mHeight / 2); // 给画笔设置随机颜色 mTextPaint.setARGB(255, mRandom.nextInt(200) + 20, mRandom.nextInt(200) + 20, mRandom.nextInt(200) + 20); canvas.drawText(String.valueOf(mText.charAt(i - 1)), (i - 1) * charLength * 1.6f + 30, mHeight * 2 / 3f, mTextPaint); //画完一定要把画布转回原来的位置,不然会影响后面的绘制 canvas.restore(); } // 绘制干扰点 for (PointF pointF : mPoints) { mPointPaint.setARGB(255, mRandom.nextInt(200) + 20, mRandom.nextInt(200) + 20, mRandom.nextInt(200) + 20); canvas.drawPoint(pointF.x, pointF.y, mPointPaint); } //绘制干扰线 for (Path path : mPaths) { mPathPaint.setARGB(255, mRandom.nextInt(200) + 20, mRandom.nextInt(200) + 20, mRandom.nextInt(200) + 20); canvas.drawPath(path, mPathPaint); } }
- 7.随机生成字符串和数值,网上找的,一搜能搜一大片。
/** * 随机生成字符串和数值 * * @param length length * @return String */ public static String getCharAndNum(int length) { String val = ""; Random random = new Random(); for (int i = 0; i < length; i++) { // 输出字母还是数字 String charOrNum = random.nextInt(2) % 2 == 0 ? "char" : "num"; // 字符串 if ("char".equalsIgnoreCase(charOrNum)) { // 取得大写字母还是小写字母 int choice = random.nextInt(2) % 2 == 0 ? 65 : 97; val += (char) (choice + random.nextInt(26)); } else if ("num".equalsIgnoreCase(charOrNum)) { // 数字 val += String.valueOf(random.nextInt(10)); } } return val; }
后记,Android自定义View并没有想象中的那么可怕和恐怖,只要能静下心来去思考多在纸上写写画画就能发现其实并没有多难,网上各大论坛都有很优秀的博客和教程,我们并不是独自战斗,而是站在巨人的肩膀上前行,共勉之。附一张我学习自定义View的手稿,难堪的字体可以忽略。
附送源码地址:https://github.com/wutq/Verification
阅读全文
1 0
- 自定义View学习之验证码
- android自定义view之刷新验证码
- 自定义View初学笔记之验证码
- Android 自定义View之随机生成图片验证码
- 【Android自定义View实战】之获取验证码倒计时按钮
- Android自定义View入门之简单验证码控件
- Android 自定义View之随机生成图片验证码
- Android 自定义View之正方形验证码输入框
- 自定义View-输入验证码
- Android 自定义View (验证码)
- 自定义view之一:自定义验证码控件
- Android 学习之自定义View
- 学习笔记之自定义view
- Android学习之自定义View
- 学习笔记之自定义View
- 自定义View学习笔记之自定义圆
- android 自定义控件以及自定义view学习(随机验证码生成)
- android 自定义控件以及自定义view学习(随机验证码生成)
- [C++][IO]fstream用法
- [Multimedia][图像]PNG格式分析
- C++设计模式
- 配置linux防火墙
- [C++][IO]cout 的不同进制格式输出
- 自定义View学习之验证码
- ZOJ 1039 Number Game(SG博弈+状压+记忆化搜索)
- JAVA-初步认识-第二章-算术运算符2续
- [C++][编程风格]C++命名规则
- 计算录音显示时长——BigDecimal
- vim编程入门基础
- [C++][编程风格]优质代码的十条建议
- [Multimedia][MPEG]MPEG-2基本介绍
- Springmvc 绑定