175

我需要对一系列 EditText 进行表单输入验证。我正在使用 OnFocusChangeListeners 在用户键入每个内容后触发验证,但这并不符合最后一个 EditText 的预期。

如果我在输入最终的 EditText 时单击“完成”按钮,则 InputMethod 将断开连接,但从技术上讲,EditText 上的焦点永远不会丢失(因此永远不会发生验证)。

最好的解决方案是什么?

我应该监视 InputMethod 何时与每个 EditText 解除绑定而不是焦点更改时吗?如果是这样,怎么做?

4

14 回答 14

157

你为什么不使用TextWatcher

由于您有许多EditText要验证的框,我认为以下内容适合您:

  1. 您的活动实现android.text.TextWatcher接口
  2. 您将 TextChanged 侦听器添加到您的 EditText 框
txt1.addTextChangedListener(this);
txt2.addTextChangedListener(this);
txt3.addTextChangedListener(this);
  1. 在被覆盖的方法中,您可以使用afterTextChanged(Editable s)如下方法
@Override
public void afterTextChanged(Editable s) {
    // validation code goes here
}

Editable s并不能真正帮助找到正在更改的 EditText 框的文本。但是您可以直接检查 EditText 框的内容,例如

String txt1String = txt1.getText().toString();
// Validate txt1String

用同样的方法。我希望我很清楚,如果我清楚,它会有所帮助!:)

编辑:对于更清洁的方法,请参阅下面克里斯托弗佩里的回答

于 2010-05-18T09:28:24.293 回答
134

TextWatcher 对我来说有点冗长,所以我做了一些更容易下咽的东西:

public abstract class TextValidator implements TextWatcher {
    private final TextView textView;

    public TextValidator(TextView textView) {
        this.textView = textView;
    }

    public abstract void validate(TextView textView, String text);

    @Override
    final public void afterTextChanged(Editable s) {
        String text = textView.getText().toString();
        validate(textView, text);
    }

    @Override
    final public void beforeTextChanged(CharSequence s, int start, int count, int after) { /* Don't care */ }

    @Override
    final public void onTextChanged(CharSequence s, int start, int before, int count) { /* Don't care */ }
}

像这样使用它:

editText.addTextChangedListener(new TextValidator(editText) {
    @Override public void validate(TextView textView, String text) {
       /* Validation code here */
    }
});
于 2012-08-07T03:10:57.193 回答
97

如果您在发生错误时想要漂亮的验证弹出窗口和图像,您可以使用我在此处描述的类的setError方法EditText

使用 setError 的屏幕截图来自链接帖子的作者 Donn Felker

于 2011-11-23T20:59:11.423 回答
27

为了减少验证逻辑的冗长,我为 Android 编写了一个库。它使用注释和内置规则处理大部分日常验证。有@TextRule, @NumberRule, @Required, @Regex, @Email, @IpAddress,@Password等约束,

您可以将这些注释添加到您的 UI 小部件引用并执行验证。它还允许您异步执行验证,这对于检查远程服务器的唯一用户名等情况非常理想。

项目主页上有一个关于如何使用注释的示例。您还可以阅读相关的博客文章,其中我编写了有关如何编写自定义验证规则的示例代码。

这是一个描述库使用的简单示例。

@Required(order = 1)
@Email(order = 2)
private EditText emailEditText;

@Password(order = 3)
@TextRule(order = 4, minLength = 6, message = "Enter at least 6 characters.")
private EditText passwordEditText;

@ConfirmPassword(order = 5)
private EditText confirmPasswordEditText;

@Checked(order = 6, message = "You must agree to the terms.")
private CheckBox iAgreeCheckBox;

Rule该库是可扩展的,您可以通过扩展类来编写自己的规则。

于 2012-10-23T14:06:07.373 回答
12

更新的方法 - TextInputLayout:

Google 最近推出了设计支持库,其中有一个名为TextInputLayoutsetErrorEnabled(boolean)的组件,它支持通过和显示错误setError(CharSequence)

如何使用它?

第 1 步:用 TextInputLayout 包装 EditText:

  <android.support.design.widget.TextInputLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:id="@+id/layoutUserName">

    <EditText
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:hint="hint"
      android:id="@+id/editText1" />

  </android.support.design.widget.TextInputLayout>

第 2 步:验证输入

// validating input on a button click
public void btnValidateInputClick(View view) {

    final TextInputLayout layoutUserName = (TextInputLayout) findViewById(R.id.layoutUserName);
    String strUsername = layoutLastName.getEditText().getText().toString();

    if(!TextUtils.isEmpty(strLastName)) {
        Snackbar.make(view, strUsername, Snackbar.LENGTH_SHORT).show();
        layoutUserName.setErrorEnabled(false);
    } else {
        layoutUserName.setError("Input required");
        layoutUserName.setErrorEnabled(true);
    }
}

我在我的Github 存储库上创建了一个示例,如果您愿意,请查看该示例!

于 2015-07-25T10:16:24.463 回答
11

这是从这里开始的很好的解决方案

InputFilter filter= new InputFilter() { 
    public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) { 
        for (int i = start; i < end; i++) { 
            String checkMe = String.valueOf(source.charAt(i));

            Pattern pattern = Pattern.compile("[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz123456789_]*");
            Matcher matcher = pattern.matcher(checkMe);
            boolean valid = matcher.matches();
            if(!valid){
                Log.d("", "invalid");
                return "";
            }
        } 
        return null; 
    } 
};

edit.setFilters(new InputFilter[]{filter}); 
于 2012-08-14T08:16:16.027 回答
8

我写了一个扩展 EditText 的类,它本身支持一些验证方法,实际上非常灵活。

当前,正如我所写, 通过xml 属性验证方法本机支持的是:

  1. α
  2. 字母数字
  3. 数字
  4. 通用正则表达式
  5. 字符串空性

你可以在这里查看

希望你喜欢它 :)

于 2012-05-24T21:44:22.620 回答
7

我发现 InputFilter 更适合验证 android 上的文本输入。

这是一个简单的例子: 如何在 Android 中使用 InputFilter 来限制 EditText 中的字符?

您可以添加一个 Toast 来向用户反馈您的限制。还要检查 android:inputType 标签。

于 2011-10-05T08:49:34.217 回答
6

我需要进行字段内验证而不是字段间验证,以测试我的值在一种情况下是无符号浮点值,而在另一种情况下是有符号浮点值。这似乎对我有用:

    <EditText
        android:id="@+id/x" 
        android:background="@android:drawable/editbox_background" 
        android:gravity="right" 
        android:inputType="numberSigned|numberDecimal" 
    />

请注意,“numberSigned|numberDecimal”中不能有任何空格。例如:“numberSigned | numberDecimal”将不起作用。我不确定为什么。

于 2011-01-01T23:50:09.367 回答
5

这看起来很有希望,这正是文档为我订购的:

编辑文本验证器

    public void onClickNext(View v) {
    FormEditText[] allFields    = { etFirstname, etLastname, etAddress, etZipcode, etCity };
    
    
    boolean allValid = true;
    for (FormEditText field: allFields) {
        allValid = field.testValidity() && allValid;
    }
    
    if (allValid) {
        // YAY
    } else {
        // EditText are going to appear with an exclamation mark and an explicative message.
    }
}

自定义验证器加上这些内置:

  • 正则表达式:用于自定义正则表达式
  • numeric:仅用于数字字段
  • alpha:仅用于 alpha 字段
  • alphaNumeric : 你猜怎么着?
  • personName:检查输入的文本是人名还是姓氏。
  • personFullName:检查输入的值是否是完整的全名。
  • email:检查该字段是否为有效的电子邮件
  • creditCard :使用Luhn 算法检查该字段是否包含有效的信用卡
  • phone:检查该字段是否包含有效的电话号码
  • domainName:检查该字段是否包含有效的域名(始终通过 API Level < 8 的测试)
  • ipAddress:检查该字段是否包含有效的 IP 地址
  • webUrl : 检查该字段是否包含有效的 url (总是通过 API Level < 8 的测试)
  • date:检查该字段是否是有效的日期/日期时间格式(如果设置了 customFormat,请使用 customFormat 进行检查)
  • nocheck:除了字段是否为空之外,它不检查任何内容。
于 2013-12-18T07:36:39.510 回答
2

您可以通过聆听用户点击键盘上的“完成”按钮来获得所需的行为,还可以在我的帖子“Android 表单验证 - 正确方式”中查看有关使用 EditText 的其他提示

示例代码:

mTextView.setOnEditorActionListener(new TextView.OnEditorActionListener() {
    @Override
    public boolean onEditorAction(TextView view, int actionId, KeyEvent event) {
        if (actionId == EditorInfo.IME_ACTION_DONE) {                    
            validateAndSubmit();
            return true;
        }
        return false;
    }});  
于 2013-08-04T21:33:57.637 回答
2

在 main.xml 文件中

您可以放置​​以下属性来验证只有字母字符可以在edittext中接受。

做这个 :

  android:entries="abcdefghijklmnopqrstuvwxyz"
于 2014-04-07T04:53:46.263 回答
0

对于电子邮件和密码验证尝试

  if (isValidEmail(et_regemail.getText().toString())&&etpass1.getText().toString().length()>7){
      if (validatePassword(etpass1.getText().toString())) {
      Toast.makeText(getApplicationContext(),"Go Ahead".....
      }
      else{

       Toast.makeText(getApplicationContext(),"InvalidPassword".....
       }

}else{

 Toast.makeText(getApplicationContext(),"Invalid Email".....
}


public boolean validatePassword(final String password){
    Pattern pattern;
    Matcher matcher;
    final String PASSWORD_PATTERN = "^(?=.*[0-9])(?=.*[A-Z])(?=.* 
    [@#$%^&+=!])(?=\\S+$).{4,}$";
    pattern = Pattern.compile(PASSWORD_PATTERN);
    matcher = pattern.matcher(password);

    return matcher.matches();
}

public final static boolean isValidEmail(CharSequence target) {
    if (target == null)
        return false;

    return android.util.Patterns.EMAIL_ADDRESS.matcher(target).matches();
}
于 2018-05-10T07:04:58.873 回答
-2

我已经为 android 创建了这个库,您可以在其中轻松验证材料设计 EditText 和 EditTextLayout,如下所示:

    compile 'com.github.TeleClinic:SmartEditText:0.1.0'

那么你可以像这样使用它:

<com.teleclinic.kabdo.smartmaterialedittext.CustomViews.SmartEditText
    android:id="@+id/passwordSmartEditText"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:setLabel="Password"
    app:setMandatoryErrorMsg="Mandatory field"
    app:setPasswordField="true"
    app:setRegexErrorMsg="Weak password"
    app:setRegexType="MEDIUM_PASSWORD_VALIDATION" />

<com.teleclinic.kabdo.smartmaterialedittext.CustomViews.SmartEditText
    android:id="@+id/ageSmartEditText"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:setLabel="Age"
    app:setMandatoryErrorMsg="Mandatory field"
    app:setRegexErrorMsg="Is that really your age :D?"
    app:setRegexString=".*\\d.*" />

然后你可以像这样检查它是否有效:

    ageSmartEditText.check()

有关更多示例和自定义检查存储库 https://github.com/TeleClinic/SmartEditText

于 2017-12-22T09:09:59.530 回答