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
A more easier solution I would suggest is by creating a drawable resource file (@drawable/rectangular_border) :-
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<stroke
android:width="2dp"
android:color="@color/colorAccent" />
<corners
android:radius="10dp"
/>
<solid
android:color="@android:color/transparent"
/>
</shape>
And in you XML file replace the background of you TextInputEditText with the following resource file i.e -
<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/rectangular_border"
android:ellipsize="end"
android:inputType="textMultiLine|textNoSuggestions"
android:text="@={viewModel.value}"
style="@style/MyEditTextStyle" />
</android.support.design.widget.TextInputLayout>
In this way you will be the background color won't change completely, only the borders on errors or counter overflow. Hope this solution solves your problem :).
Arranging the accepted solution with https://stackoverflow.com/a/40379564/2914140 and https://stackoverflow.com/a/44744941/2914140, I wrote another class. When an EditText has a special background (background_1) it changes to a background_2 on error. When the error disappears, it again returns to background_1. No red fill is executed.
public class YourTextInputLayout extends TextInputLayout {
private Drawable drawable1; // Normal background.
private Drawable drawable2; // Error background.
public YourTextInputLayout(Context context) {
super(context);
}
public YourTextInputLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public YourTextInputLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void drawableStateChanged() {
super.drawableStateChanged();
replaceBackground();
}
@Override
public void setError(@Nullable final CharSequence error) {
super.setError(error);
replaceBackground();
}
public void setDrawable1(Drawable drawable) {
this.drawable1 = drawable;
}
public void setDrawable2(Drawable drawable) {
this.drawable2 = drawable;
}
private void replaceBackground() {
EditText editText = getEditText();
if (editText != null) {
editText.setBackground(isErrorEnabled() ? drawable2 : drawable1);
Drawable drawable = editText.getBackground();
if (drawable != null) {
drawable.clearColorFilter();
}
}
}
}
In your activity/fragment call after initialization in onCreate() / onCreateView():
YourTextInputLayout inputLayout = ...;
inputLayout.setDrawable1(ContextCompat.getDrawable(getContext(), R.drawable.background_1));
inputLayout.setDrawable2(ContextCompat.getDrawable(getContext(), R.drawable.background_2));
In your XML layout call it by:
<com.example.package.YourTextInputLayout
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<EditText
...
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.
I had same problem; after searching and hit & run I found so simple way to solve this problem-
Try this easiest way -
<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>
And 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>
Now the original shape (@drawable/rectangle_black_border_background) will be like -
<?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>
And the original shape (@drawable/rectangle_blue_border_background) will be like -
<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>
Note- The ** lines are too important -
**Note - ** change your padding value and top value from item and the solid color according to need (You can also remove solid color line also).
That's it :-) Happy coding +1