Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android TextInputLayout icon in error (or hint) text

I am using a TextInputLayoutHelper widget in order to follow the material guidelines for floating label inputs. It currently looks like this:

floating input label with error message

My code

In my activities onCreate function, I have:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    val passwordInputLayout = this.findViewById<TextInputLayoutHelper>(R.id.input_layout_password)
    passwordInputLayout.error = "8+ characters and at least one uppercase letter, a number, and a special character (\$, #, !)"
    passwordInputLayout.isErrorEnabled = true
}

and my widget in my xml looks like...

<TextInputLayout
    android:id="@+id/input_layout_password"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:theme="@style/EditTextTheme"
    app:errorEnabled="true"
    app:errorTextAppearance="@style/ErrorAppearance"
    app:passwordToggleDrawable="@drawable/asl_password_visibility"
    app:passwordToggleEnabled="true"
    app:passwordToggleTint="?colorControlNormal">

    <EditText
        android:id="@+id/password_edit_text"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:ems="10"
        android:hint="@string/set_a_password"
        android:inputType="textPassword"
        android:singleLine="true" />

</TextInputLayout>

What I want to do

I want to put an icon in the error/hint text (the exclamation triangle) to the right of the error text.

mock up of input with error icon

My Attempt

Attempt 1

I found an implementation which uses setError(text, drawable) but I am using Kotlin to setError is not available.

So I tried:

val warningIcon = ResourcesCompat.getDrawable(resources, R.drawable.ic_warning_black_24dp, null)
warningIcon?.setBounds(0, 0, warningIcon.intrinsicWidth, warningIcon.intrinsicHeight)

passwordInputLayout.error = "8+ characters and at least one uppercase letter, a number, and a special character (\$, #, !) $warningIcon"

but that does not render the drawable, only a string of the resource path.

Attempt 2

I found another one that overrides the TextInputLayoutHelper in order to set a drawable next to the text. As you can see, setError only contains the interface override fun setError(error: CharSequence?) which does not have a parameter for drawable.

override fun setError(error: CharSequence?) {
    super.setError(error)

    val warningIcon = ResourcesCompat.getDrawable(resources, R.drawable.ic_warning_black_24dp, null)
    warningIcon?.setBounds(0, 0, warningIcon.intrinsicWidth, warningIcon.intrinsicHeight)
    // mHelperView is a TextView used in my custom `TextInputLayout` override widget
    mHelperView!!.setCompoundDrawables(null, null, warningIcon, null)
}

Is there an override or built in "Android way" to add this icon next to the error/hint text?

like image 385
james Avatar asked Jan 16 '18 15:01

james


People also ask

How do I remove TextInputLayout error?

You should be able to call TextInputLayout. setErrorEnabled(false) to hide the error TextView and calling TextInputLayout. setError(error) now internally calls TextInputLayout. setErrorEnabled(true) if the error isn't null or empty.

What is TextInputLayout Android?

TextInputLayout is a view container that is used to add more features to an EditText. It acts as a wrapper for EditText and has some features like: Floating hint. Animation that can be disabled or enabled. Error labels that display error messages when an error occurs.

How do I remove the default padding in TextInputLayout?

You can just set the start and end padding on the inner EditText to 0dp. Here's a screenshot with Show Layout Bounds turned on so you can see that the hints go all the way to the edge of the view. Save this answer.


1 Answers

You can use SpannableString with ImageSpan like this

val errorDrawable = ContextCompat.getDrawable(context!!, R.drawable.ic_error)
your_text_input_layout.error = SpannableString("your string").apply {
                setSpan(ImageSpan(errorDrawable, ImageSpan.ALIGN_BASELINE), 0, 1, Spanned.SPAN_INCLUSIVE_EXCLUSIVE)
like image 120
Cassian Avatar answered Sep 22 '22 10:09

Cassian