返回

透过现象看本质:EditText中maxLength属性失效之谜

Android

现象:maxLength失效的谜题

在Android开发中,EditText控件经常被用来获取用户输入。为了限制用户输入的长度,我们可以通过xml属性maxLength来设置最大长度。然而,有时我们可能会遇到这样的情况:即使我们在xml中设置了maxLength属性,但代码中调用了setFilters方法后,maxLength属性却失效了,允许用户输入超过最大长度的内容。

本质:setFilters与maxLength的博弈

为了理解这一现象的根源,我们需要深入到EditText的源码中。在TextView的构造函数中,我们可以看到以下代码:

public TextView(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    ...
    if (attrs != null) {
        final TypedArray a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.TextView, defStyleAttr, 0);
        ...
        if (a.hasValue(com.android.internal.R.styleable.TextView_maxLength)) {
            mMaxLength = a.getInt(com.android.internal.R.styleable.TextView_maxLength, Integer.MAX_VALUE);
        }
        ...
    }
    ...
}

这段代码表明,maxLength属性是在TextView的构造函数中解析的,并将其值存储在mMaxLength字段中。当用户输入超过mMaxLength时,TextView会自动截断输入内容,以确保不超过最大长度。

然而,如果我们在代码中调用了setFilters方法,情况就会发生变化。setFilters方法允许我们为EditText控件设置过滤器,这些过滤器可以对用户输入的内容进行各种处理,例如过滤掉某些字符或将输入的内容转换为大写。当我们调用setFilters方法后,EditText控件会创建一个新的InputFilter[]数组,并将新数组作为参数传递给父类的setFilters方法。

在父类的setFilters方法中,会执行以下代码:

public void setFilters(InputFilter[] filters) {
    if (filters != null) {
        if (filters.length > 0) {
            mFilters = filters;
            invalidate();
        } else {
            mFilters = null;
        }
    }
    ...
}

这段代码表明,当我们调用setFilters方法时,EditText控件会将新的InputFilter[]数组赋值给mFilters字段。这意味着,原先存储在mMaxLength字段中的最大长度信息将被覆盖,从而导致maxLength属性失效。

解决:重建maxLength的屏障

既然我们已经了解了maxLength属性失效的根源,那么我们就可以采取相应的措施来解决这个问题。最简单的方法就是在调用setFilters方法之前,先将maxLength属性的值存储在一个临时变量中,然后在setFilters方法之后,再将临时变量中的值重新赋值给mMaxLength字段。这样,就可以确保maxLength属性不会被覆盖,从而恢复其原有的功能。

当然,我们也可以选择不使用setFilters方法,而是通过其他方式来实现对用户输入内容的处理。例如,我们可以使用TextWatcher来监听用户的输入,并在用户输入超过最大长度时,弹出提示框提醒用户。

结语

通过本文的分析,我们了解了EditText中maxLength属性失效的根源,并提供了两种解决方法。希望这篇文章能够帮助Android开发人员更好地理解EditText控件,并在实际开发中避免遇到类似的问题。