TextInputLayout.setError()清除错误后留下空白间隙

76

最近我使用了TextInputLayout和它的setError()方法。我的问题是,当我通过调用setError(null)来清除错误时,会在底部留下很多空白。

正常:

Normal

有错误:

With error

清除错误后:

After clearing error

经过查看源代码,我发现他们将视图设置为INVISIBLE而不是GONE

.setListener(new ViewPropertyAnimatorListenerAdapter() {
@Override
public void onAnimationEnd(View view) {
    view.setVisibility(INVISIBLE); // here it is

    updateLabelVisibility(true);
} }).start();
我在想为什么会这样?如何解决以避免空白间隔?

你是为它提供自己的动画吗? - Sharath
10个回答

170

查看文档以获取更多信息

public void setErrorEnabled (boolean enabled)

它表示

这个布局中错误功能是否启用。在通过setError(CharSequence)设置错误消息之前启用此功能,将意味着当显示错误时,此布局不会改变大小。

基于此,请尝试在setError()之前设置setErrorEnabled(true),并在setError(null)之后设置setErrorEnabled(false)


2
你说得对。谢谢你指出这一点。但它仍然占用了很多空间,而且在预览布局时也无法预测。我仍然不明白为什么他们设计成这样。 - Mangesh
其实我也不太确定为什么他们这样实现,是的,使用View.GONE可以节省空间,但是如果一些复杂的视图组件位于TextInputLayout下方,并且它们需要被向下移动,那么可能会出现问题。 - harshitpthk
1
在设置错误时,它会扩展。但将错误设置为null或将setErrorEnabled设置为false不会使布局折叠回去。 - Sagar Nayak
2
setError调用setErrorEnabled(true)内部。 - Florian Walther
太好了!我为此创建了两个扩展函数:fun TextInputLayout.showError(errorText: String) { this.isErrorEnabled = true this.error = errorText }fun TextInputLayout.removeError() { this.isErrorEnabled = false this.error = null } - Jose Flavio Quispe Irrazábal

55

setErrorEnabled(false)方法将清除额外的空间,因此在调用setError(null)之后调用它。


这个回应给了我预期的结果。谢谢。 - Laranjeiro
谢谢。正是我所需要的! - ice_chrysler
为什么需要 setError(null) - Sam Chen

6
不要使用 setErrorEnabled(boolean) 方法,因为它无法在第二次显示错误信息。
public class MyTextInputLayout extends android.support.design.widget.TextInputLayout {

public MyTextInputLayout(Context context) {
    super(context);
}

public MyTextInputLayout(Context context, AttributeSet attrs) {
    super(context, attrs);
}

public MyTextInputLayout(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
}

@Override
public void setError(@Nullable CharSequence error) {
    super.setError(error);

    View layout = getChildAt(1);
    if (layout != null) {
        if (error != null && !"".equals(error.toString().trim())) {
            layout.setVisibility(VISIBLE);
        } else {
            layout.setVisibility(GONE);
        }
    }
}
}

那么只需使用setError(errorMessage);setError(null);即可。

工作正常,但它会立即删除文本。有没有一种方法可以使其动画化? - Andrew

4
请参见此页面。Google将在未来的支持库版本中发布修复程序。其中说明如下:

If you want to fix it now you can extends the TextInputLayout and override the setErrorEnabled() method, but I cant guarantee the backward compatibility. Because its some danger to change state in TextInputLayout.

public class TextInputLayout extends android.support.design.widget.TextInputLayout{


    public TextInputLayout(Context context) {
        super(context);
    }

    public TextInputLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public TextInputLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    public void setErrorEnabled(boolean enabled) {
        super.setErrorEnabled(enabled);
        if (enabled) {
            return;
        }
        if (getChildCount() > 1) {
            View view = getChildAt(1);
            if (view != null) {
                view.setVisibility(View.GONE);
            }
        }
    }
}

1
@HRaval,这个 bug 已经在支持库 v23.2.0 中修复了,但我还没有验证过。 - Shaode Lu
1
@ShaodeLu,我已经检查了23.3.0版本,他们没有修复它。 - Dennis Zinkovski

4

TextInputLayout的源代码如下所示:

如果需要清除错误,请使用

til.setErrorEnabled(false);

这将隐藏错误文本并将底部空间拉伸至其标准大小。
如果需要重新设置错误,请使用。
til.setError("Your text");

该函数自动调用 til.setErrorEnabled(true),因为它默认您需要错误功能。


4

这是 Kotlin 中解决问题的扩展功能:

fun TextInputLayout.clearError() {
    error = null
    isErrorEnabled = false
}

4

我创建了一个自定义视图来避免重复的代码,并覆盖setError方法。

    public class UserInputView extends TextInputLayout {

        public UserInputView(Context context) {
           this(context, null);
        }

        public UserInputView(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
        }

        public UserInputView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
        }

        @Override
        public void setError(@Nullable CharSequence error) {
            boolean isErrorEnabled = error != null;
            setErrorEnabled(isErrorEnabled);
            super.setError(error);
        }

     }

0

以下代码运行正常

    textInputLatout.getEditText().addTextChangedListener(new TextWatcher() {
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {

        }

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
            if (s.length() < 1) {
               textInputLayout.setErrorEnabled(true);
                textInputLayout.setError("Please enter a value");
            }

            if (s.length() > 0) {
                textInputLayout.setError(null);
                textInputLayout.setErrorEnabled(false);
            }

        }

        @Override
        public void afterTextChanged(Editable s) {

        }
    });

0

通过使用 mTextInputLayout.setErrorEnabled(false); 我解决了这个问题。


-3

那么你应该这样覆盖它:

@Override
public void onAnimationEnd(View view)
{
    view.setVisibility(GONE); // <-- this is where you make it GONE

    updateLabelVisibility(true); 
}

或者尝试在按钮或其他你正在使用的地方使用这个:

final Button btn = (Button) findViewById(R.id.btn);
btn.setVisibility(View.GONE); //<--- makes the button gone

1
抱歉,我不明白你在说什么。 - Mangesh
一个视图可以是任何东西,例如一个按钮。 - superkytoz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接