Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
255 views
in Technique[技术] by (71.8m points)

android - Do not change TextInputLayout background on error

I would like to have an EditText with the background as a "normal" EditText but with the error handling of a TextInputEditText (error message appearing at the bottom, and not the "!" drawable appearing).

I got something like this :

<android.support.design.widget.TextInputLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:setError="@{viewModel.error}">

    <android.support.design.widget.TextInputEditText

        android:layout_width="match_parent"
        android:layout_height="wrap_content"

        android:background="@drawable/simple_edit_text_background"
        android:ellipsize="end"
        android:inputType="textMultiLine|textNoSuggestions"
        android:text="@={viewModel.value}"

        style="@style/MyEditTextStyle" />

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

But it seems that when I set error on the TextInputLayout it changes the background drawable(which is, in normal TextInputEditText, the underline) to the color of the error TextView.

And so this is how my EditText looks like : enter image description here

We can see it in the code of TextInputLayout within the following method :

private void updateEditTextBackground() {
    if (mEditText == null) {
        return;
    }

    Drawable editTextBackground = mEditText.getBackground();
    if (editTextBackground == null) {
        return;
    }

    ensureBackgroundDrawableStateWorkaround();

    if (android.support.v7.widget.DrawableUtils.canSafelyMutateDrawable(editTextBackground)) {
        editTextBackground = editTextBackground.mutate();
    }

    if (mErrorShown && mErrorView != null) {
        // Set a color filter of the error color
        editTextBackground.setColorFilter(
                AppCompatDrawableManager.getPorterDuffColorFilter(
                        mErrorView.getCurrentTextColor(), PorterDuff.Mode.SRC_IN));
    } else if (mCounterOverflowed && mCounterView != null) {
        // Set a color filter of the counter color
        editTextBackground.setColorFilter(
                AppCompatDrawableManager.getPorterDuffColorFilter(
                        mCounterView.getCurrentTextColor(), PorterDuff.Mode.SRC_IN));
    } else {
        // Else reset the color filter and refresh the drawable state so that the
        // normal tint is used
        DrawableCompat.clearColorFilter(editTextBackground);
        mEditText.refreshDrawableState();
    }
}

The code's block that update the backgroud color is here :

if (mErrorShown && mErrorView != null) {
    // Set a color filter of the error color
    editTextBackground.setColorFilter(
            AppCompatDrawableManager.getPorterDuffColorFilter(
                    mErrorView.getCurrentTextColor(), PorterDuff.Mode.SRC_IN));
}

Because this method is private I can't override it and because I still wants my error TextView's color to be red I can't see any solution so far. Any idea?

One solution could maybe to reset background color to its default value just after setError would have been called but is their any callback with a method like onError that will be fired once an error is set to a TextView/EditText?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I manage to resolve this myself by overriding TextInputLayout like this :

public class NoChangingBackgroundTextInputLayout extends TextInputLayout {
    public NoChangingBackgroundTextInputLayout(Context context) {
        super(context);
    }

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

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

    @Override
    public void setError(@Nullable CharSequence error) {
        ColorFilter defaultColorFilter = getBackgroundDefaultColorFilter();
        super.setError(error);
        //Reset EditText's background color to default.
        updateBackgroundColorFilter(defaultColorFilter);
    }

    @Override
    protected void drawableStateChanged() {
        ColorFilter defaultColorFilter = getBackgroundDefaultColorFilter();
        super.drawableStateChanged();
        //Reset EditText's background color to default.
        updateBackgroundColorFilter(defaultColorFilter);
    }

    private void updateBackgroundColorFilter(ColorFilter colorFilter) {
        if(getEditText() != null && getEditText().getBackground() != null)
            getEditText().getBackground().setColorFilter(colorFilter);
    }

    @Nullable
    private ColorFilter getBackgroundDefaultColorFilter() {
        ColorFilter defaultColorFilter = null;
        if(getEditText() != null && getEditText().getBackground() != null)
            defaultColorFilter = DrawableCompat.getColorFilter(getEditText().getBackground());
        return defaultColorFilter;
    }
}

So as we can see it, it reset the EditText's background to its default color after setError has been called but also in the method drawableStateChanged() because the red color filter is set when losing/getting the focus on an EditText with error too.

I'm not convinced that this is the best solution but if I don't get any better solutions, I'll mark it as resolved in meantime.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...