TextInputLayout error message size

老子叫甜甜 提交于 2019-12-12 03:47:26

问题


Is there a way to force the TextInputLayout error message to take a single line ?

I tried to place app:errorTextAppearance="@style/error_appearance" on the TextInputLayout with the error_appearance style containing :

<item name="android:maxLines">1</item>
<item name="android:ellipsize">end</item>
<item name="android:inputType">text</item>

and it does not work. Changing the color works however. I don't get it, the mErrorView is just a TextView, it should work.


回答1:


It's true the the error text is just a TextView, but a TextAppearance style affects only the text itself, not how the TextView lays it out (apart from sizing considerations due to those attributes). You can set the error text's size, typeface, color, etc. with the errorTextAppearance, but you can't set the ellipsize or maxLines on the View with that.

Since the error is just a TextView, we can just set the desired attributes ourselves. We could iterate over all of the descendant Views of the TextInputLayout, but that's a little unwieldy, and isn't very reliable, since the TextInputLayout could hold more than one TextView that is not its EditText. I usually prefer reflection for things like this.

The error TextView is created when the setErrorEnabled() method is called with true, and its field is nullified if the method is called with false. Rather than try to track all this externally, it would be easier to subclass TextInputLayout, and set the desired attributes on the error TextView when it gets created. Note that setErrorEnabled() is called automatically during instantiation, so there's no need to explicitly invoke the method to enable this.

For example:

public class CustomTextInputLayout extends TextInputLayout {

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

    @Override
    public void setErrorEnabled(boolean enabled) {
        super.setErrorEnabled(enabled);

        if (!enabled) {
            return;
        }

        try {
            Field errorViewField = TextInputLayout.class.getDeclaredField("mErrorView");
            errorViewField.setAccessible(true);
            TextView errorView = (TextView) errorViewField.get(this);
            if (errorView != null) {
                errorView.setMaxLines(1);
                errorView.setEllipsize(TextUtils.TruncateAt.END);
            }
        }
        catch (Exception e) {
            // At least log what went wrong
            e.printStackTrace();
        }
    }
}

This is a drop-in replacement for TextInputLayout, and you can use it in your layouts just as you would the regular class.

<com.mycompany.myapp.CustomTextInputLayout
    android:id="@+id/til"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <android.support.design.widget.TextInputEditText
        android:id="@+id/edit_text"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

</com.mycompany.myapp.CustomTextInputLayout>


For completeness' sake, I'll include the following, which can be used in lieu of the above method, to find the first TextView child of a TextInputLayout, and set the desired attributes. In a basic, default TextInputLayout, the error TextView should be the first one found. If you'd like an additional check, you can compare the text from the found child to that set as the error on the TextInputLayout.

// Returns true if found
private static boolean findErrorView(ViewGroup vg) {
    final int count = vg.getChildCount();
    for (int i = 0; i < count; ++i) {
        final View child = vg.getChildAt(i);
        if(child instanceof ViewGroup) {
            if(findErrorView((ViewGroup) child)) {
                return true;
            }
        }
        else if (child.getClass().equals(TextView.class)) {
            setAttributes((TextView) child);
            return true;
        }
    }
    return false;
}

private static void setAttributes(TextView t) {
    t.setMaxLines(1);
    t.setEllipsize(TextUtils.TruncateAt.END);
}

TextInputLayout is a ViewGroup, so you can just call findErrorView() directly with your instance of that, either inside a subclass, or externally. Still do be aware, though, the the error TextView is created anew whenever the error is enabled, and destroyed when it's disabled. These settings will not persist through that.


N.B. – At the time of writing this answer, the error TextView was not assigned an ID when created, thus the need for the reflective and iterative methods above. However, as kjurkovic alludes to in their answer, the error TextView is now assigned an ID of R.id.textinput_error, in recent versions of the support library. This precludes the need for the methods described in this answer, though the style explanation and the description of the TextView's instantiation and nulling is still pertinent.

I would also mention that the counter TextView is now assigned an ID, as well, of R.id.textinput_counter, in case anyone should happen upon this post in search of information on that.




回答2:


you can fetch error TextView by id

TextView errorView = textInputLayout.findViewById(R.id.textinput_error);
errorView.setMaxLines(1);
errorView.setSingleLine(true);


来源:https://stackoverflow.com/questions/40706163/textinputlayout-error-message-size

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!