13

enter image description hereI have make an EditText inside TextInputLayout. I am setting a drawableLeft to an EditText at runtime in my code, but as soon as I add the drawableLeft the floating hint inside TextInputLayout shifts to right leaving the space equal to drawable width. But I dont want that space in hint, so help me to resolve this!!

Anupriya
  • 1,663
  • 3
  • 17
  • 28

3 Answers3

38

TextInputLayout uses a library-restricted helper class – CollapsingTextHelper – to manipulate its hint text. The instance of this helper is private, and none of the attributes associated with its layout are exposed, so we'll need to use a little reflection to get access to it. Furthermore, its properties are set and recalculated every time the TextInputLayout is laid out, so it makes sense to subclass TextInputLayout, override its onLayout() method, and make our adjustments there.

import android.content.Context
import android.graphics.Rect
import android.util.AttributeSet
import com.google.android.material.textfield.TextInputLayout

class CustomTextInputLayout @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = com.google.android.material.R.attr.textInputStyle
) : TextInputLayout(context, attrs, defStyleAttr) {

    private val collapsingTextHelper = try {
        TextInputLayout::class.java.getDeclaredField("collapsingTextHelper")
            .apply { isAccessible = true }.get(this)
    } catch (e: Exception) {
        null
    }

    private val recalculateMethod = collapsingTextHelper?.let { helper ->
        try {
            helper.javaClass.getDeclaredMethod("recalculate")
        } catch (e: Exception) {
            null
        }
    }

    private val collapsedBounds = collapsingTextHelper?.let { helper ->
        try {
            helper.javaClass.getDeclaredField("collapsedBounds")
                .apply { isAccessible = true }.get(helper) as Rect
        } catch (e: Exception) {
            null
        }
    }

    override fun onLayout(
        changed: Boolean,
        left: Int,
        top: Int,
        right: Int,
        bottom: Int
    ) {
        super.onLayout(changed, left, top, right, bottom)

        val edit = editText ?: return
        val helper = collapsingTextHelper ?: return
        val recalculate = recalculateMethod ?: return
        val bounds = collapsedBounds ?: return

        bounds.left = edit.left + edit.paddingLeft
        try {
            recalculate.invoke(helper)
        } catch (e: Exception) {
            // fail silently
        }
    }
}

The custom class is a drop-in replacement for the regular TextInputLayout. For example:

<com.example.app.CustomTextInputLayout
    android:id="@+id/text_input_layout"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:hint="Model (Example i10, Swift, etc.)"
    app:hintTextAppearance="@style/TextLabel">

    <com.google.android.material.textfield.TextInputEditText
        android:id="@+id/edit_text"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:drawableLeft="@drawable/bmw"
        android:text="M Series" />

</com.example.app.CustomTextInputLayout>

Screenshot showing the adjusted hint alignment.

Mike M.
  • 38,532
  • 8
  • 99
  • 95
  • 1
    add these lines to the proguard rules so that it will still work on your production build: `-keep class android.support.design.widget.TextInputLayout{ *; }` `-keep class android.support.design.widget.CollapsingTextHelper{ *; }` – Tim Oct 03 '18 at 15:08
  • This latest version doesn't seem to require any special ProGuard rules, but I'm not sure why; e.g., maybe something else is already keeping those classes and members, or maybe something changed in the build tools, etc. If anyone runs into any issues, please leave a comment. – Mike M. Mar 18 '23 at 05:07
  • If there are any problems with the reflection or ProGuard or whatever, [this answer](https://stackoverflow.com/a/45511397) shows a slightly different approach that puts the custom class in the library package, therefore giving it direct access to the relevant field and method. You might get a library restriction error, but it can be suppressed. Aside from that, the only downside might be that Material Components' `TextInputLayout` figures the bounds differently 'cause of all its new bells and whistles, so things might not line up correctly with just the basic padding calculations shown there. – Mike M. Mar 18 '23 at 05:51
-1

Yes, Its a common problem that I faced recently.I solved it with simple one line code: Place a padding between your hint and drawbleleft by using drawble padding. If you are adding drawble at runtime simply add drawblepadding in xml before hand or you can dynamically add drawble padding.

W4R10CK
  • 5,502
  • 2
  • 19
  • 30
DevKRos
  • 422
  • 2
  • 15
-2
 editText.setCompoundDrawablePadding(your padding value);

Try it and let me know. It worked for me.

Preetika Kaur
  • 1,991
  • 2
  • 16
  • 23