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