出错时不要更改TextInputLayout后台

MHo*_*gge 13 android android-textinputlayout

我想将一个带有背景的EditText作为"普通"EditText,但是对TextInputEditText进行错误处理(错误消息显示在底部,而不是"!"drawable出现).

我有这样的事情:

<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>
Run Code Online (Sandbox Code Playgroud)

但似乎当我在TextInputLayout上设置错误时,它将背景drawable(在普通的TextInputEditText中,下划线)更改为错误TextView的颜色.

这就是我的EditText的样子: 在此输入图像描述

我们可以在以下方法中的TextInputLayout代码中看到它:

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

更新背景颜色的代码块在这里:

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

因为这个方法是私有的我不能覆盖它,因为我仍然希望我的错误TextView的颜色为红色,到目前为止我看不到任何解决方案.任何的想法?

一个解决方案可能setError是在调用之后将背景颜色重置为其默认值,但是onError一旦将错误设置为TextView/EditText,它们的任何回调都会被触发吗?

MHo*_*gge 33

我设法通过重写TextInputLayout来解决这个问题,如下所示:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

因此,我们可以看到它,它在调用setError之后将EditText的背景重置为其默认颜色,但也在方法中,drawableStateChanged()因为在丢失/获得焦点的EditText时也设置了红色滤镜.

我不相信这是最好的解决方案,但如果我没有得到任何更好的解决方案,我会在此期间将其标记为已解决.

  • 好的解决方案 再一次,我们需要使用黑客来克服Android糟糕的设计. (4认同)

Baj*_*dda 8

我有同样的问题; 搜索并点击并运行后,我找到了解决此问题的简单方法 -

尝试这种最简单的方法 -

               <android.support.design.widget.TextInputLayout
                    android:id="@+id/til_description"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="8dp"
                    app:errorText="@{feedbackViewModel.descError}"
                    >

                    <EditText
                        style="@style/TextInputLayoutEditText"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:background="@drawable/desc_field_selector"
                        **android:paddingTop="10dp"**
                        **android:paddingBottom="7dp"**
                        android:gravity="top|left"
                        android:hint="@string/description"
                        android:inputType="textMultiLine"
                        android:lines="4"
                        android:onTextChanged="@{(text, start, before, count) -> feedbackViewModel.onDescriptionTextChanged(text)}"
                        android:scrollHorizontally="false"
                        android:scrollbarStyle="insideInset"
                        android:scrollbars="vertical"
                        android:text="@={feedbackViewModel.description}"/>

                </android.support.design.widget.TextInputLayout>
Run Code Online (Sandbox Code Playgroud)

android:background ="@ drawable/desc_field_selector" -

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/rectangle_blue_border_background"
          android:state_pressed="true"/>
    <item android:drawable="@drawable/rectangle_blue_border_background"
          android:state_enabled="true"
          android:state_focused="true"
          android:state_window_focused="true"/>
    <item android:drawable="@drawable/rectangle_black_border_background"/>
</selector>
Run Code Online (Sandbox Code Playgroud)

现在原始形状(@ drawable/rectangle_black_border_background)将会像 -

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    **<item android:state_focused="false" android:top="5dp">**
        <shape>
            **<solid android:color="@android:color/transparent"/>**
            <stroke android:width="1dp" android:color="@android:color/secondary_text_light"/>
            <corners android:radius="5dp"/>
        </shape>
    </item>
</layer-list>
Run Code Online (Sandbox Code Playgroud)

原始形状(@ drawable/rectangle_blue_border_background)将如下 -

<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    **<item android:state_focused="true" android:top="5dp">**
        <shape>
            **<solid android:color="@android:color/transparent"/>**
            <stroke android:width="@dimen/one_dip" android:color="@color/colorAccent"/>
            <corners android:radius="5dp"/>
        </shape>
    </item>
</layer-list>
Run Code Online (Sandbox Code Playgroud)

注意 -**线太重要了 -

  1. paddingTop ="10dp"android:paddingBottom ="7dp" - >将浮动标签向上移动到边框形状,否则看起来不太好.
  2. android:top ="5dp" - 对于将浮动标签移动到矩形形状非常重要.
  3. 实体android:color ="@ android:color/transparent" - 这种纯色形状将是透明的,因此当出现错误时,您将看到一个透明的颜色.看一看 -

**注意 - **根据需要更改您的填充值和顶部值以及纯色(您也可以删除纯色线).

在此输入图像描述

就是这样:-)快乐编码+1