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