Anupriya Anupriya - 1 month ago 17
Android Question

Adding a drawableLeft to an EditText shifts the hint towards right, if edittext is inside TextInputlayout

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!!

Answer

TextInputLayout uses a 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.support.design.widget.CollapsingTextHelper;
import android.support.design.widget.TextInputLayout;
import android.util.AttributeSet;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class CustomTextInputLayout extends TextInputLayout {
    private Object collapsingTextHelper;
    private Rect bounds;
    private Method recalculateMethod;

    public CustomTextInputLayout(Context context) {
        this(context, null);
    }

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

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

        init();
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);

        adjustBounds();
    }

    private void init() {
        try {
            Field cthField = TextInputLayout.class.getDeclaredField("mCollapsingTextHelper");
            cthField.setAccessible(true);
            collapsingTextHelper = cthField.get(this);

            Field boundsField = collapsingTextHelper.getClass().getDeclaredField("mCollapsedBounds");
            boundsField.setAccessible(true);
            bounds = (Rect) boundsField.get(collapsingTextHelper);

            recalculateMethod = collapsingTextHelper.getClass().getDeclaredMethod("recalculate");
        }
        catch (NoSuchFieldException | IllegalAccessException | NoSuchMethodException e) {
            collapsingTextHelper = null;
            bounds = null;
            recalculateMethod = null;
            e.printStackTrace();
        }
    }

    private void adjustBounds() {
        if (collapsingTextHelper == null) {
            return;
        }

        try {
            bounds.left = getEditText().getLeft() + getEditText().getPaddingLeft();
            recalculateMethod.invoke(collapsingTextHelper);
        }
        catch (InvocationTargetException | IllegalAccessException | IllegalArgumentException e) {
            e.printStackTrace();
        }
    }
}

This custom class is a drop-in replacement for the regular TextInputLayout, and you would use it the same way. For example:

<com.mycompany.myapp.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">

    <android.support.design.widget.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.mycompany.myapp.CustomTextInputLayout>

screenshot

Comments