项目需求讨论-摆脱EditText内容规则的枯燥判断

大家好,又到了新的一期的项目需求讨论。我想大家在开发APP,肯定会有很多需要填入EditText内容的界面,比如注册界面,修改密码界面。这些界面都会有很多个相应的EditText。同时每个EditText需要填写的内容不同,所以就造成我们对于每个EditText进行相应的判断。

比如下面的界面:

可能我们需要输入“用户名”、“地址”、“邮箱”、“电话”。然后下面可能就有一个“注册”的按钮,当我们按下“注册”按钮的时候。我们可能平时都是这么做的:

  1. 获取了四个EditText的对象
private EditText mNameEditText;
private EditText mAddressEditText;
private EditText mEmailEditText;
private EditText mPhoneEditText;
mNameEditText = (EditText) findViewById(R.id.nameEditText);
mAddressEditText = (EditText) findViewById(R.id.addressEditText);
mEmailEditText = (EditText) findViewById(R.id.emailEditText);
mPhoneEditText = (EditText) findViewById(R.id.phoneEditText);
  1. 获取他们的内容,从上往下,一个个判断他是不是为空,如果为空,我们就提示用户漏填了某个内容:
if(TextUtils.isEmpty(mNameEditText.getText().toString()){
       Toast.makeText(this, "用户名是必填项,请输入内容", Toast.LENGTH_SHORT).show();
       return;
}
....
....
....
  1. 当每个都填了内容后,你可能还要相应的不同的EditText还有相应的规则,比如我们上面已经判断了用户名不为空了。然后我们的APP有规定,用户名的长度不能小于5同时不能大于10,然后你又要写:
int nameLength = mNameEditText.getText().toString().length();
   if(nameLength < 5 || nameLength > 10){
       Toast.makeText(this, "用户名长度不能小于5且不能大于10", Toast.LENGTH_SHORT).show();
       return;
   }
  1. 然后你还要对相应的EditText去一个个判断邮箱规则,电话规则,如果还要“密码”的EditText,一般同事还有一个“确认密码”的EditText,这时候你不仅要第一个EditText符合密码规则,然后还要判断二个EditText的内容是不是相等。反正是麻烦至极,而且代码基本都是很多地方都是重复,让阅读也变得很差。

  所以程序员本着对于这些代码的懒惰原则。我就去寻找相关的优秀的工具,这不,本文的主角出场了:

**android-saripaar
**

这里我们分别对于本文主角的使用功能来进行介绍:

基本使用方法:

比如我们上面讲到的用户名不能为空,我们看下用saripaar是怎么来使用

  1. 在我们定义的EditText的引用上方,添加相应功能的注解即可
@NotEmpty
private EditText mNameEditText;
  1. 创建Validator对象,并且设置EditText中的内容规则判断后的回调事件:
Validator mValidator = new Validator(this);
mValidator.setValidationListener(new Validator.ValidationListener() {
        @Override
        public void onValidationSucceeded() {
            //符合我们添加的相关规则,验证成功
        }

        @Override
        public void onValidationFailed(List<ValidationError> errors) {
            //不符合我们添加的相关规则,验证失败
        }
});
  1. 在某种条件下(比如按下注册按钮)调用验证方法:
mValidator.validate();

基本用法就是上面那样,可能大家会说,老司机你就这样??这个功能也太少了吧。别急,容许老司机一步步来介绍相关详细内容。


基本的注解:

比如有一些:
@NotEmpty :非空
@Length: 长度
@Email: 邮箱
@Password:密码(默认是6位)
@ConfirmPassword:确认密码
@Checked:CheckBox是否被选中
@Length:长度判断
IpAddress:ip地址判断

等,我就不列举了,直接看图吧


@Order:

我们一般来说界面上会有好几个EditText,比如name,email,address三个输入框,我们会对三个输入框都设置相关的规则,这时候每个app中对于这些输入框的判断的顺序有所要求,比如先是判断name,然后依次往下判断,但有些可能先判断address等。
所以@Order就是用来让我们验证好几个EditText时来进行排序的。

@NotEmpty
@Order(1)
private EditText mNameEditText;

@NotEmpty
@Order(2)
private EditText mAddressEditText;

@Email
@Order(3)
private EditText mEmailEditText;

这时候大家可能就会问了。你这里设置了@Order,那顺序体现在哪里呢?就在我们上面设置过的Listener中:

@Override
public void onValidationFailed(List<ValidationError> errors) {
    
}

我们可以看到,这个失败的方法里面的参数是List<ValidationError> errors
我们可以看下ValidationError的源码里面有这么几个方法:

public View getView() {
    return view;
}

public List<Rule> getFailedRules() {
    return failedRules;
}

public String getCollatedErrorMessage(final Context context) {
    StringBuilder stringBuilder = new StringBuilder();
    for (Rule failedRule : failedRules) {
        String message = failedRule.getMessage(context).trim();
        if (message.length() > 0) {
            stringBuilder.append(message).append('\n');
        }
    }
    return stringBuilder.toString().trim();
}

我们一眼就会发现getView这个方法就是我们所需要的,没错,如果我们有好几个EditText都不符合规则,在List```<ValidationError>中就会按照我们写的@Order``的顺序来进行排序。

比如我们想让EditText不符合规则的时候出现:


我们只需要:

@Override
public void onValidationFailed(List<ValidationError> errors) {
    for (ValidationError error : errors){
        ((EditText) error.getView()).setError("不符合规则");
    }
}

也许有人会说。我希望name错了的时候就提示name,后面的就不管了。报第一个不符合规则的错误,然后有人会说errors.get(0).getView()获取,当然这样是可以的,但是saripaar已经帮我考虑到了:

//全部不符合规则
mValidator.setValidationMode(Validator.Mode.BURST);

//按照顺序第一个不符合规则的
mValidator.setValidationMode(Validator.Mode.IMMEDIATE);

我们设置了后,同样的代码就变成了:


(message = ""):

有小伙伴会说,你上面提示的内容的都是不符合规则,我们想要不同的EditText不符合规则后提示不同的内容,还记得我们上面ValidationError有个方法getCollatedErrorMessage(context),没错,我们可以给每个EditText设置不同的message,然后在验证失败后,显示相应的message即可:

@NotEmpty(message = "名字不能为空")
private EditText mNameEditText;

@Override
public void onValidationFailed(List<ValidationError> errors) {
    for (ValidationError error : errors){
        ((EditText) error.getView()).setError(error.getCollatedErrorMessage(OrderedValidateActivity.this));
    }
}

sequence:

我们有时候对于一个EditText会有多种要求,比如不仅不能为空,而且同时要符合邮箱的标准,这时候我们对于验证也希望有验证顺序,比如先判断是否为空,如果为空,直接就提示错误了。如果不为空再判断是不是符合邮箱的规则。

@NotEmpty(sequence = 1, message = "不能为空")
@Email(sequence = 2, message = "不符合邮箱规则")
private EditText mEmailEditText;

这时候你会发现这个EditText就会按照你所规定的规则顺序来判断。
但这里注意了,上面提过我们获取message是用

error.getCollatedErrorMessage(context);

因为上面我们一个EditText只添加了一个规则判断,所以无所谓,比如我这里添加了二个,我们再看的时候会变成怎么样?


没错,虽然判断规则的顺序的确是按照我们写的那样,但是,你发现了,error.getCollatedErrorMessage(context);方法获取到的message的内容是全部不符合规则的message的集合。但我们想要的是非空的时候先提示不能为空,然后在不为空的条件下,不是邮箱格式,再提示邮箱不符合邮箱格式。

还记不记得我们已经介绍了上面ValidationError的二个方法,还有一个方法getFailedRules()没介绍过,没错,我们可以用这个,从字面意思我们就可以理解,获取到失败的规则的集合,而且这个集合的顺序就是我们设置的sequence的顺序,我们这么写:

for (ValidationError error : errors){

    ((EditText) error.getView()).
    setError(error.getFailedRules().get(0)
    .getMessage(OrderedValidateActivity.this));
        
}

我们获取第一个不符合的规则的Message即可。
看效果:


@Optional:

很多时候我们一些信息是非必填的,比如还是email,我们可以为空,但是如果你填了,那么一定就要符合邮箱的规则,这时候@Optional就起到作用了:

@Optional 
@Email 
EditText mEmailEditText;

你可以不填,这时候验证是通过的,但是如果你填了内容,就一定要符合email规则。使用起来什么方便。


validateTill 和 validateBefore

我们上面在最后起到验证功能是调用了

mValidator.validate();

同时它还提供了:

mValidator.validateTill(view);
mValidator.validateBefore(view);

从字面意思我们就知道,到某个View为止的规则检验,及某个View前的规则检验。

validateTill:比如有a,b,c,d四个View,并且order的顺序相对应也是1,2,3,4,
比如当前四个View都不符合规则,并且你调用了validateTill(c),那么我们的List<ValidationError> errors中就包含了a,b,c。如果你调用了validateBefore(c),则List<ValidationError> errors就包含了a,b,也就是比传入的View的Order小的会被包含。

同时你在使用的时候会发现他们三个方法都有另外的重载方法,分别是:

validate(boolean);
validateTill(view ,boolean);
validateBefore(view,boolean);

当那个Boolean值为true的时候,就是说我们可以把验证的过程放在后台的AsyncTask中去执行。


@AssertTrue 和 @AssertFalse

我们有些输入框可能不是通用的规则,像邮箱啊,电话号码什么的,比如某个输入框的判断规则是"青蛙要fly好帅",当EditText的内容是这个的时候才能认为通过。这时候我们就要添加自己的规则。可以使用@AssertTrue来判断是否符合你定义的规则。

@AssertTrue
private EditText testEt;

mValidator.registerAdapter(EditText.class, new ViewDataAdapter<EditText, Boolean>() {
    @Override
    public Boolean getData(EditText view) throws ConversionException {
        return "青蛙要fly好帅".equals(view.getText().toString());
    }

    @Override
    public <T extends Annotation> boolean containsOptionalValue(EditText view, T ruleAnnotation) {
        return false;
    }
});

Custom Annotation

当然我们还可以自己制定相关的注解,比如我现在自己写一个@CoolBoy,用来判断EditText是否符合我写的相关内容:

CoolBoy.java

@ValidateUsing(CoolBoyRule.class)
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface CoolBoy {

    @StringRes int messageResId()   default -1;
    String message()                default "不能说青蛙要fly不帅气";
    int sequence()                  default -1;
}

CoolBoyRule.java

public class CoolBoyRule extends AnnotationRule<CoolBoy, String> {

    protected CoolBoyRule(final CoolBoy coolBoy) {
        super(coolBoy);
    }

    @Override
    public boolean isValid(String data) {
        return "青蛙要fly是个帅哥".equals(data);
    }
}

最后一步:
在Validator.java中添加我们刚声明好的注解:

SARIPAAR_REGISTRY.register(
    ConfirmEmail.class, ConfirmPassword.class, CreditCard.class,
    Digits.class, Domain.class, Email.class, Future.class,
    IpAddress.class, Isbn.class, Length.class, NotEmpty.class,
    Password.class, Past.class, Pattern.class, Url.class, CoolBoy.class);

//在最后添加了我们的CoolBoy.class
    

然后在我们的代码中使用:

 @CoolBoy
 private EditText mNameEditText;

补充

我们在validator.java中还可以看到其他的申明等:

static {
    // CheckBoxBooleanAdapter
    SARIPAAR_REGISTRY.register(CheckBox.class, Boolean.class,
        new CheckBoxBooleanAdapter(),
        AssertFalse.class, AssertTrue.class, Checked.class);

    // RadioGroupBooleanAdapter
    SARIPAAR_REGISTRY.register(RadioGroup.class, Boolean.class,
        new RadioGroupBooleanAdapter(),
        Checked.class);

    // RadioButtonBooleanAdapter
    SARIPAAR_REGISTRY.register(RadioButton.class, Boolean.class,
        new RadioButtonBooleanAdapter(),
        AssertFalse.class, AssertTrue.class, Checked.class);

    // SpinnerIndexAdapter
    SARIPAAR_REGISTRY.register(Spinner.class, Integer.class,
        new SpinnerIndexAdapter(),
        Select.class);

    // TextViewDoubleAdapter
    SARIPAAR_REGISTRY.register(DecimalMax.class, DecimalMin.class);

    // TextViewIntegerAdapter
    SARIPAAR_REGISTRY.register(Max.class, Min.class);

    // TextViewStringAdapter
    SARIPAAR_REGISTRY.register(
        ConfirmEmail.class, ConfirmPassword.class, CreditCard.class,
        Digits.class, Domain.class, Email.class, Future.class,
        IpAddress.class, Isbn.class, Length.class, NotEmpty.class,
        Password.class, Past.class, Pattern.class, Url.class, CoolBoy.class);
}

哈哈,更多的demo大家也可以看:
**android-saripaar
**
里面有相关的testdemo的使用。欢迎大家吐槽。哈哈,还是老话,哪里错了,希望大家能指出。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,033评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,725评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,473评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,846评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,848评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,691评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,053评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,700评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,856评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,676评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,787评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,430评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,034评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,990评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,218评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,174评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,526评论 2 343

推荐阅读更多精彩内容