设计给的验证码输入效果是这样的: 校验码固定为6位数字,未输入位用一条横线占位,注意,这不是-,而是一条横线,中间的间隔比其他地方的间隔大。这显然不是简单的EditText能实现的。参考了TextView源码后,自定义了一个View实现这个效果。 实现原理,自定义View继承自View,点击时弹出键盘接收用户输入,在onDraw时绘画。代码如下:
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.text.InputType;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputMethodManager;
import com.pocketdigi.plib.core.PLog;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import me.mailang.secretary.R;
/**
* 验证码输入View
* Created by fhp on 14/12/18.
*/
public class VerifyCodeView extends View {
StringBuilder verifyCodeBuilder;
//一个字符或横线占用的宽度
private int characterWidth;
//一个数字后中间的间隔
private int centerSpacing;
//两字符间隔
private int characterSpacing;
private int textSize;
Paint textPaint;
float textBaseY;
public VerifyCodeView(Context context, AttributeSet attrs) {
super(context, attrs);
//能获取焦点才能弹出软键盘
setFocusableInTouchMode(true);
verifyCodeBuilder = new StringBuilder(6);
textPaint=new Paint(Paint.ANTI_ALIAS_FLAG);
centerSpacing=getResources().getDimensionPixelSize(R.dimen.reg_verifycode_center_spacing);
characterSpacing=getResources().getDimensionPixelSize(R.dimen.reg_verifycode_character_spacing);
textSize=getResources().getDimensionPixelSize(R.dimen.reg_verifycode_textsize);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
//在View上点击时弹出软键盘
InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Context.INPUT\_METHOD\_SERVICE);
//反射调隐藏的focusIn方法,如果不调,在VerifyCodeView之前有EditText等可输入控件时,不会弹出输入法
//可能有其他google提供的方法,但我没找到
Class immClass = imm.getClass();
try {
Method focusIn = immClass.getDeclaredMethod("focusIn", View.class);
focusIn.invoke(imm,this);
} catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
e.printStackTrace();
}
imm.viewClicked(this);
imm.showSoftInput(this, 0);
return super.onTouchEvent(event);
}
@Override
public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
//定义软键盘样式为数字键盘
outAttrs.inputType = InputType.TYPE\_CLASS\_NUMBER;
return super.onCreateInputConnection(outAttrs);
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
//接收按键事件,67是删除键(backspace),7-16就是0-9
if (keyCode == 67 && verifyCodeBuilder.length() > 0) {
verifyCodeBuilder.deleteCharAt(verifyCodeBuilder.length() - 1);
//重新绘图
invalidate();
} else if (keyCode >= 7 && keyCode <= 16 && verifyCodeBuilder.length() < 6) {
verifyCodeBuilder.append(keyCode - 7);
invalidate();
}
//到了6位自动隐藏软键盘
if (verifyCodeBuilder.length() >= 6) {
InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Context.INPUT\_METHOD\_SERVICE);
imm.hideSoftInputFromWindow(getWindowToken(), 0);
}
return super.onKeyDown(keyCode, event);
}
/\*\*
\* 获取输入的校验码
\* @return
*/
public String getVerifyCodeStr() {
return verifyCodeBuilder.toString();
}
/\*\*
\* 设置显示的校验码
\* @param verifyCode
*/
public void setVerifyCode(String verifyCode) {
if(verifyCodeBuilder.length()>0) {
verifyCodeBuilder.delete(0, verifyCodeBuilder.length());
}
verifyCodeBuilder.append(verifyCode);
invalidate();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//计算一个字符的宽度
if(characterWidth==0) {
int w = getWidth() - getPaddingLeft() - getPaddingRight();
characterWidth=(w-centerSpacing-4*characterSpacing)/6;
}
textPaint.setTextSize(textSize);
textPaint.setTextAlign(Paint.Align.CENTER);
Paint.FontMetrics fontMetrics = textPaint.getFontMetrics();
float fontHeight = fontMetrics.bottom - fontMetrics.top;
if(textBaseY==0)
textBaseY = getHeight() - (getHeight() - fontHeight) / 2 - fontMetrics.bottom;
//写已输入的验证码
if(verifyCodeBuilder.length()>0) {
textPaint.setColor(getResources().getColor(R.color.white));
String verifyCodeStr = getVerifyCodeStr();
char\[\] chars = verifyCodeStr.toCharArray();
int x,y=(int)textBaseY;
for(int i=0;i