在开发中总会遇到输入框的输入规则限制
比如 电话输入框电话号码的校验,密码规则的校验等 ,我们通常做法是提交操作时对每个输入框的输入内容进行校验,很多的if else ,代码看起来很乱,其实我们可以用反射注解的方式去声明一些判断规则这样会更好,代码可读性更强。
java反射文章推荐:http://www.jianshu.com/p/5b3acad0f025
下面我们通过一个例子去讲解注解方式去实现表达式的校验
这个包下定义的是注解实体类,每一个类都是一个注解规则,如Index类代码:
这个包下都是一些javabean, 如AttrBean代码:
BaseBean基础类,每个bean是一个规则javabean类,
结果回调类
处理回调校验结果
上面主要是校验器和工具类:
public class ValidateUtil { /** * 设置校验view的信息 * @param view * @param isEditText * @param msg * @param validateResult */ private static void setViewInfo(Object view, boolean isEditText, String msg, IValidateResult validateResult) { if (isEditText) { validateResult.onValidateError(msg, ((EditText) view)); } else { validateResult.onValidateError(msg, null); } } /** * 不可为空 * @param view * @param isEt * @param msg * @param validateResult * @return */ public static boolean notNull(Object view, boolean isEt, String msg, IValidateResult validateResult) { if (TextUtils.isEmpty(((TextView) view).getText().toString())) { setViewInfo(view, isEt, msg, validateResult); return true; } return false; } /** * 判断是否为空 * @param view * @return */ public static boolean isNull(Object view) { if (view == null) throw new NullPointerException("view can not be null"); if (TextUtils.isEmpty(((TextView) view).getText().toString())) { return true; } return false; } /** * 根据正则表达式校验 * @param view * @param isEt * @param bean * @param validateResult * @return */ public static boolean checkPattern(Object view, boolean isEt, PatternBean bean, IValidateResult validateResult) { if (isNull(view)) return true; Pattern r = Pattern.compile(bean.pattern); Matcher m = r.matcher(((TextView) view).getText().toString()); if (!m.matches()) { setViewInfo(view, isEt, bean.msg, validateResult); return true; } return false; } /** * 最大长度校验 * @param view * @param isEt * @param bean * @param validateResult * @return */ public static boolean maxLenght(Object view, boolean isEt, LengthBean bean, IValidateResult validateResult) { if (isNull(view)) return true; if (((TextView) view).getText().toString().length() > bean.length) { setViewInfo(view, isEt, bean.msg, validateResult); return true; } return false; } }
public class ValidateManager { private static final String TAG = "ValidateManager"; /** * 注册的页面 */ private static Map> registList = new HashMap<>(); /** * 类型 */ private static final String TYPE_NOTNULL = "NotNull"; private static final String TYPE_PATTERN = "PATTERN"; private static final String TYPE_MAXLENGTH = "MAXLENGTH"; private static final String TYPE_MINLENGTH = "MINLENGTH"; private static final String TYPE_PASSWORDFIRST = "PASSWORD_FIRST"; private static final String TYPE_PASSWORDSECOND = "PASSWORD_SECOND"; private static final String TYPE_SKIP = "SKIP"; public static void check(Object activity, boolean isSkip, IValidateResult validateResult) { if (activity == null || validateResult == null) return; List list = registList.get(activity); if (list == null) return; for (AttrBean attrBean : list) { if (attrBean.index == null) { return; } } Collections.sort(list, new Comparator() { public int compare(AttrBean arg0, AttrBean arg1) { return arg0.index.compareTo(arg1.index); } }); for (AttrBean attrBean : list) { for (Basebean bean : attrBean.annos) { if (isSkip) { if (TYPE_SKIP.equals(attrBean.annos.getLast().type)) { break; } } if (TYPE_NOTNULL.equals(bean.type)) { if (ValidateUtil.notNull(attrBean.view, attrBean.isEditText, bean.msg, validateResult)) { return; } } else if (TYPE_PATTERN.equals(bean.type)) { if (ValidateUtil.checkPattern(attrBean.view, attrBean.isEditText, (PatternBean) bean, validateResult)) { return; } } else if (TYPE_MAXLENGTH.equals(bean.type)) { if (ValidateUtil.maxLenght(attrBean.view, attrBean.isEditText, (LengthBean) bean, validateResult)) { return; } } else if (TYPE_MINLENGTH.equals(bean.type)) { if (ValidateUtil.minLenght(attrBean.view, attrBean.isEditText, (LengthBean) bean, validateResult)) { return; } } else if (TYPE_PASSWORDFIRST.equals(bean.type)) { if (ValidateUtil.isNull(attrBean.view)) { return; } pwd1Attr = attrBean; } else if (TYPE_PASSWORDSECOND.equals(bean.type)) { if (ValidateUtil.password(attrBean, pwd1Attr, (PasswordBean) bean, validateResult)) { return; } pwd1Attr = null; } } } validateResult.onValidateSuccess(); pwd1Attr = null; } private static AttrBean pwd1Attr = null; private static class ValidateRegRunnable implements Runnable { Object target; public ValidateRegRunnable(Object target) { this.target = target; } @Override public void run() { try { Class clazz = target.getClass(); for (Field field : clazz.getDeclaredFields()) { if (field.isAnnotationPresent(NotNull.class) || field.isAnnotationPresent(Pattern.class) || field.isAnnotationPresent(MaxLength.class) || field.isAnnotationPresent(MinLength.class) || field.isAnnotationPresent(Index.class) || field.isAnnotationPresent(PasswordFirst.class) || field.isAnnotationPresent(PasswordSecond.class)) { if (field.getType() != EditText.class) { throw new RuntimeException("annotation must be on the EditText"); } field.setAccessible(true); List editTextMap = registList.get(target); if (editTextMap == null) { editTextMap = new LinkedList<>(); registList.put(target, editTextMap); } AttrBean attr = new AttrBean(); attr.name = field.getName(); attr.view = field.get(target); if (field.getType() == EditText.class) { attr.isEditText = true; } else if (field.getType() == TextView.class) { attr.isEditText = false; } if (attr.annos == null) { attr.annos = new LinkedList<>(); } editTextMap.add(attr); if (field.isAnnotationPresent(NotNull.class)) attr.annos.add(validateType(field, TYPE_NOTNULL)); if (field.isAnnotationPresent(Pattern.class)) attr.annos.add(validateType(field, TYPE_PATTERN)); if (field.isAnnotationPresent(MaxLength.class)) { attr.annos.add(validateType(field, TYPE_MAXLENGTH)); if (attr.view != null && attr.isEditText) { int length = field.getAnnotation(MaxLength.class).length(); ((EditText) attr.view).setFilters(new InputFilter[]{new InputFilter.LengthFilter(length)}); } } if (field.isAnnotationPresent(MinLength.class)) attr.annos.add(validateType(field, TYPE_MINLENGTH)); if (field.isAnnotationPresent(PasswordFirst.class)) { attr.annos.add(validateType(field, TYPE_PASSWORDFIRST)); if (attr.view != null && attr.isEditText) { ((EditText) attr.view).setTransformationMethod(PasswordTransformationMethod.getInstance()); } } if (field.isAnnotationPresent(PasswordSecond.class)) { attr.annos.add(validateType(field, TYPE_PASSWORDSECOND)); if (attr.view != null && attr.isEditText) { ((EditText) attr.view).setTransformationMethod(PasswordTransformationMethod.getInstance()); } } if (field.isAnnotationPresent(Index.class)) attr.index = field.getAnnotation(Index.class).value(); if (field.isAnnotationPresent(Skip.class)) attr.annos.add(validateType(field, TYPE_SKIP)); } } } catch (Exception e) { e.printStackTrace(); } } } /** * 根据不同类型校验 * @param field * @param type * @return * @throws IllegalAccessException */ private static Basebean validateType(Field field, String type) throws IllegalAccessException { if (type.equals(TYPE_NOTNULL)) { NotNull notnull = field.getAnnotation(NotNull.class); NotNullBean bean = new NotNullBean(); bean.msg = notnull.msg(); bean.type = type; return bean; } else if (type.equals(TYPE_PATTERN)) { Pattern re = field.getAnnotation(Pattern.class); PatternBean reBean = new PatternBean(); reBean.msg = re.msg(); reBean.type = TYPE_PATTERN; reBean.pattern = re.pattern(); return reBean; } else if (type.equals(TYPE_MAXLENGTH)) { MaxLength anno = field.getAnnotation(MaxLength.class); LengthBean bean = new LengthBean(); bean.msg = anno.msg(); bean.type = TYPE_MAXLENGTH; bean.length = anno.length(); return bean; } else if (type.equals(TYPE_MINLENGTH)) { MinLength anno = field.getAnnotation(MinLength.class); LengthBean bean = new LengthBean(); bean.msg = anno.msg(); bean.type = TYPE_MINLENGTH; bean.length = anno.length(); return bean; } else if (type.equals(TYPE_PASSWORDFIRST)) { PasswordBean bean = new PasswordBean(); bean.type = TYPE_PASSWORDFIRST; return bean; } else if (type.equals(TYPE_PASSWORDSECOND)) { PasswordSecond anno = field.getAnnotation(PasswordSecond.class); PasswordBean bean = new PasswordBean(); bean.msg = anno.msg(); bean.type = TYPE_PASSWORDSECOND; return bean; } else if (type.equals(TYPE_SKIP)) { Basebean bean = new Basebean(); bean.type = TYPE_SKIP; return bean; } return null; } /** * 注册 * @param target */ public static void regist(final Object target) { new Thread(new ValidateRegRunnable(target)).start(); } /** * 解注册 * @param target */ public static void unregist(Object target) { registList.remove(target); } }
我只贴出了部分代码,可以根据项目实际需求去添加规则,再把相应的校验器代码扩展到这个类里。
我们在主页面使用 按照正常的注解方式去实现 如下:
index是校验的顺序,需要正则表达式校验的输入框我们通过pattern去通过正则表达式去实现,minLength和maxLength是最小最大长度校验
完成后调用ValidateManager.check(this , isSkip , this);实现校验功能,经过回调处理(isSkip是否可以忽略不校验此项)
可以对指定输入框的view进行错误提醒,比如上面 对输入框背景色设置红色等操作。需源码的留邮箱。