问题
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 View
s 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