美文网首页
Android表单输入验证框架---SmartValidate

Android表单输入验证框架---SmartValidate

作者: 封印命运 | 来源:发表于2016-11-05 09:35 被阅读1317次

    1.简介
    最近项目中涉及大量的表单填写,验证和提交,为了解决输入判断和提交判断,我使用了大量OnFocusChangeListener进行验证,不但费时费力,而且代码极其臃肿,因此自己写了一个小框架,重写了EditText的相关方法,并使用运行时注解来对输入格式进行设定.同时集成了ButterKnife的注解绑定控件ID的功能,方便大家在Activity和Fragment中初始化控件.下面是这个框架的一个小Demo.
    2.使用效果

    如图,我们创建了6个EditText框,在没有任何操作时为正常状态,如果在没有填写必填选项时点击提交,则会显示错误信息,如下:


    如果在需要填写数字的地方填写了非法数据,则会用红框圈起来(这些判断在离开焦点时也会提示出来),如图:

    这就是本程序的基本用法,下面上代码.
    3.程序源代码
    首先我们看一下这个框架是怎么用的:

    public class SmartValidateActivity extends Activity {
    
        @Inject(R.id.et_input0)
        @Validated(canNull = false, regex = RegexUtil.PHONE)
        public SmartEditText input0;
        
        @Inject(R.id.et_input1)
        @Validated(canNull = false, regex = RegexUtil.NUM_FLOAT)
        public SmartEditText input1;
        
        @Inject(R.id.et_input2)
        @Validated(regex = RegexUtil.PHONE)
        public SmartEditText input2;
        
        @Inject(R.id.et_input3)
        @Validated(canNull = false)
        public SmartEditText input3;
        
        @Inject(R.id.et_input4)
        public SmartEditText input4;
        
        @Inject(R.id.et_input5)
        @Validated(canNull = true, regex = RegexUtil.NUM_FLOAT)
        public SmartEditText input5;
        
        @Inject(R.id.bt_submit)
        public Button submit;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_smart_validate);
            initData();
        }
    
        private void initData() {
            InputValidator.init(this);
            submit.setOnClickListener(new OnClickListener() {
                
                @Override
                public void onClick(View v) {
                    // TODO Auto-generated method stub
                    if(InputValidator.validate()){
                        Toast.makeText(SmartValidateActivity.this, "验证成功!", 0).show();
                    }else{
                        Toast.makeText(SmartValidateActivity.this, "验证失败,输入有错误!", 0).show();
                    }
                }
            });
        }
    
    }
    

    可以看到我们在每个EditText前使用注解设定了该输入框的格式和是否可为空,canNull控制是否为空,regex为传入的正则;此外还实现了Inject注入控件id的功能,然后在OnCreate中调用InputValidator.init(this);即可完成初始化,在提交时判断InputValidator.validate()的返回值判断是否输入正确;

    下面我们看下框架代码:

    public class SmartEditText extends EditText {
    
        private static final String INPUT_WRONG = "input_wrong";
        private static final String GET_WRONG = "get_wrong";
        private String regexLine;
        private boolean canNullLine = true;
    
        public SmartEditText(Context context) {
            super(context);
            // TODO Auto-generated constructor stub
        }
    
        public SmartEditText(Context context, AttributeSet attrs) {
            super(context, attrs);
            // TODO Auto-generated constructor stub
        }
    
        
        @Override
        public void setError(CharSequence error) {
    
            if (error == null) {
                setBackground(null);
            } else if (error.equals(INPUT_WRONG)) {
                setBackgroundResource(R.drawable.edittext_input_false);
            } else {
                super.setError(error);
            }
        }
    
        public void setSmartInputListener(boolean canNull, String regex) {
    
            canNullLine = canNull;
            regexLine = regex;
            if (!canNullLine) {
                setHint("此选项为必填选项!");
            }
    
            setOnFocusChangeListener(new OnFocusChangeListener() {
    
                @Override
                public void onFocusChange(View v, boolean hasFocus) {
                    // TODO Auto-generated method stub
                    if (!hasFocus) {
                        String inputContent = ((EditText) v).getText().toString().trim();
                        if (inputContent.length() > 0) {
                            if (regexLine == null) {
                                setBackground(null);
                            } else {
                                if (inputContent.matches(regexLine)) {
                                    setBackground(null);
                                } else {
                                    setError(INPUT_WRONG);
                                }
                            }
                        } else {
                            if (canNullLine) {
                                setBackground(null);
                            } else {
                                setError("此选项为必填选项!");
                            }
                        }
                    } else if (hasFocus) {
                        setBackground(null);
                    }
                }
            });
        }
        
        public boolean validate() {
            String inputContent = getText().toString().trim();
            if(inputContent.length() > 0){
                if(regexLine != null){
                    if(inputContent.matches(regexLine)){
                        setBackground(null);
                        return true;
                    }else{
                        setError(INPUT_WRONG);
                        return false;
                    }
                }
                return true;
            }else{
                if(canNullLine){
                    setBackground(null);
                    return true;
                }else{
                    setError("此选项为必填选项!");
                    return false;
                }
            }
        }
    }
    

    首先我们重写了EditText控件的SetError方法,让我们可以自定义Error发生时的动作,这里我只是让它错误时背景变红;然后增加了一个setSmartInputListener的方法,这个方法不用我们自己调用,框架会帮我们自动回调它;

    再看一下框架主类的逻辑:

    public class Annotations {
        
        public static final String NO_REGEX = "NullContent";
        
        //用于实现向控件注入ID,类似于ButterKnife的用法
        @Retention(RetentionPolicy.RUNTIME)
        @Target(ElementType.FIELD)
        public @interface Inject{
            
            int value() default -1;
            
        }
        
        //用于标记需要进行输入验证的控件,canNull控制是否可以为空,regex为正则表达式
        @Retention(RetentionPolicy.RUNTIME)
        @Target(ElementType.FIELD)
        public @interface Validated{
            
            boolean canNull() default true;
            String regex() default NO_REGEX;
            
        }
    }
    

    这是注解类,绑定ID的注解只需要一个int型参数;
    验证注解需要传入是否可空和正则,他们任何一个都可以缺省,当canNull缺省时默认为该选项可空;

    public class InputValidator {
    
        public static List<SmartEditText> inputList;
        public static boolean isChecked;
    
        public static void init(Activity activity) {
            if (inputList != null) {
                inputList.clear();
            } else {
                inputList = new ArrayList<SmartEditText>();
            }
    
            Class<? extends Activity> clazz = activity.getClass();
            Field[] fields = clazz.getDeclaredFields();
    
            for (Field field : fields) {
                field.setAccessible(true);
                if (field.isAnnotationPresent(Inject.class)) {
                    Inject annotation = field.getAnnotation(Inject.class);
                    int id = annotation.value();
                    if (id >= 0) {
                        try {
                            field.set(activity, activity.findViewById(id));
                        } catch (IllegalAccessException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        } catch (IllegalArgumentException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                    }
                }
                if (field.isAnnotationPresent(Validated.class)) {
                    Validated annotation = field.getAnnotation(Validated.class);
                    boolean canNull = annotation.canNull();
                    String regex = annotation.regex().equals(Annotations.NO_REGEX) ? null : annotation.regex();
                    Log.d("Lihao", canNull + regex);
                    SmartEditText editText;
                    try {
                        editText = (SmartEditText) (field.get(activity));
                        editText.setSmartInputListener(canNull, regex);
                        inputList.add(editText);
                    } catch (IllegalAccessException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    } catch (IllegalArgumentException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
                
            }
        }
    
        public static boolean validate() {
            isChecked = true;
            if (inputList == null) {
                return false;
            } else {
                Log.d("Lihao", inputList.toString());
                for (SmartEditText editText : inputList) {
                    if (!editText.validate()) {
    
                        isChecked = false;
                    }
                }
                return isChecked;
            }
        }
    }
    

    这个类是主类,使用反射来获取Activity中属性的注解,根据注解为EditText控件设置OnFucusChangeListener,并执行控件的ID绑定.

    好了,这就是目前这个框架的原理说明,附上GitHub地址,欢迎提出建议和Star
    https://github.com/Lihao0510/SmartValidate

    相关文章

      网友评论

          本文标题:Android表单输入验证框架---SmartValidate

          本文链接:https://www.haomeiwen.com/subject/vvowuttx.html