75

I recently used TextInputLayout and it's setError() method. The problem I'm getting is, when I clear the error by calling setError(null) it leaves so much of empty space at the bottom.

Normal:

Normal

With error:

With error

After clearing error:

After clearing error

After looking at the source, I found that they are making the view INVISIBLE instead of GONE

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

    updateLabelVisibility(true);
} }).start();

I'm wondering why is it so? How to resolve this to avoid the empty space?

Mangesh
  • 5,491
  • 5
  • 48
  • 71

10 Answers10

167

Check out the docs for

public void setErrorEnabled (boolean enabled)

It says

Whether the error functionality is enabled or not in this layout. Enabling this functionality before setting an error message via setError(CharSequence), will mean that this layout will not change size when an error is displayed.

Well based on this, try setting setErrorEnabled(true) before setError(), and, set setErrorEnabled(false) after setError(null).

Mangesh
  • 5,491
  • 5
  • 48
  • 71
harshitpthk
  • 4,058
  • 2
  • 24
  • 32
  • 2
    You are right. Thanks for pointing this out. But still it occupies a lot of space and also it is not predictable while previewing the layout. I still don't understand why they made it so. – Mangesh Dec 12 '15 at 18:17
  • well not really sure why they implemented this way, yes having View.GONE would be better to save space but could have created problems for some complex view groups if they were underneath TextInputLayout and they would have to shift down. – harshitpthk Dec 12 '15 at 18:23
  • 1
    on seterror it expands. but setting error to null or settingErrorEnabled to false does not collapse back the layout. – Sagar Nayak Feb 15 '18 at 18:53
  • 2
    setError calls setErrorEnabled(true) internally – Florian Walther Mar 24 '18 at 12:56
  • Excelent! I created two extension functions for this: 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 Jan 26 '20 at 18:39
55

Method setErrorEnabled(false) will clear the extra space, so call it after setError(null).

Mangesh
  • 5,491
  • 5
  • 48
  • 71
Mike Margulies
  • 551
  • 3
  • 5
6

Dont use setErrorEnabled(boolean), it just doesnt show up the error from the second time.

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);
        }
    }
}
}

Then just setError(errorMessage); or setError(null);

Neela
  • 1,328
  • 4
  • 23
  • 45
4

See this page. Google will release the fix in future support library version. It says,

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);
            }
        }
    }
}
Mangesh
  • 5,491
  • 5
  • 48
  • 71
Shaode Lu
  • 251
  • 1
  • 2
4

I create a custom view for avoiding repeated code and override setError method.

    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);
        }

     }
Rahul
  • 10,457
  • 4
  • 35
  • 55
4

The source code of TextInputLayout show the following: If you need to clear the error, just use

til.setErrorEnabled(false);

This will hide the error text and stretch the bottom space to its standard size.

In case you need to set the error again, just use

til.setError("Your text");

which automatically calls til.setErrorEnabled(true) as it assumes you need the error functionality.

romariomkk
  • 53
  • 2
3

This is extension in kotlin solving problem:

fun TextInputLayout.clearError() {
    error = null
    isErrorEnabled = false
}
Renetik
  • 5,887
  • 1
  • 47
  • 66
0

The following code works fine

    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) {

        }
    });
Gowsik
  • 1,096
  • 1
  • 12
  • 25
0

By using mTextInputLayout.setErrorEnabled(false); i have solved this problem

Rohit Sharma
  • 167
  • 2
  • 14
-3

Then you should override it like so:

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

    updateLabelVisibility(true); 
}

Or try this i.e. on a button or whatever you are using:

final Button btn = (Button) findViewById(R.id.btn);
btn.setVisibility(View.GONE); //<--- makes the button gone
superkytoz
  • 1,267
  • 4
  • 23
  • 43