Android开发:自定义验证码输入View

设计给的验证码输入效果是这样的:
verifycode

校验码固定为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

© 2014, 冰冻鱼. 请尊重作者劳动成果,复制转载保留本站链接! 应用开发笔记

发表评论

电子邮件地址不会被公开。 必填项已用*标注