Align baseline with a TextView which is wrapped inside a TextInputLayout

4.5k views Asked by At

I want to align the baseline of TextView "Deficient" with that of EditText "10000". They are both inside <android.support.percent.PercentRelativeLayout>

enter image description here

I tried the following, but can't get it to work.

<android.support.percent.PercentRelativeLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <android.support.design.widget.TextInputLayout
        android:id="@+id/textInputLayout_soil_nitrogen"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:layout_alignParentTop="true"
        app:layout_widthPercent="63%">

        <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="Enter N of soil"
            tools:text="10000" />

    </android.support.design.widget.TextInputLayout>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toEndOf="@id/textInputLayout_soil_nitrogen"
        android:layout_toRightOf="@id/textInputLayout_soil_nitrogen"
        app:layout_widthPercent="37%"
        tools:text="Deficient" />

</android.support.percent.PercentRelativeLayout>

Giving a top padding of 20dp to the TextView kind of does the trick, but it would've been nice to align their baselines instead. Is that even possible in this case?

I've removed the textAppearance and id attributes, btw.

5

There are 5 answers

3
AudioBubble On

Please replace below line of code

 <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toEndOf="@id/textInputLayout_soil_nitrogen"
        android:layout_toRightOf="@id/textInputLayout_soil_nitrogen"
        app:layout_widthPercent="37%"
        tools:text="Deficient" />

To

<TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBottom="@+id/textInputLayout_soil_nitrogen"
        android:layout_toEndOf="@id/textInputLayout_soil_nitrogen"
        android:layout_toRightOf="@id/textInputLayout_soil_nitrogen"
        tools:text="Deficient" />

Hope it will help you !!

1
Hitesh KR On

Check this image for verification

Please try following code

<android.support.design.widget.TextInputLayout
    android:id="@+id/textInputLayout_soil_nitrogen"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentLeft="true"
    android:layout_alignParentStart="true"
    android:layout_alignParentTop="true"
    app:layout_widthPercent="63%">

    <EditText
        android:id="@+id/editText"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="Enter N of soil"
        tools:text="10000" />

</android.support.design.widget.TextInputLayout>

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignBottom="@id/textInputLayout_soil_nitrogen"
    android:layout_toEndOf="@id/textInputLayout_soil_nitrogen"
    android:layout_toRightOf="@id/textInputLayout_soil_nitrogen"
    android:gravity="bottom|start"
    android:padding="8dp"
    android:text="Deficient"
    android:textColor="@android:color/black"
    app:layout_widthPercent="37%" />

0
Jona On

Old question but here is my solution.

Essentially the TextInputLayout isn't providing a baseline value to it's parent. We need to pipe the correct baseline of the EditText by extending TextInputLayout. This works for me, however, I'm not sure if the baseline would change due to other events from the TextInputLayout.

public class CTextInputLayout extends TextInputLayout {
    public CTextInputLayout(Context context) {
        super(context);
    }

    public CTextInputLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

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

    @Override
    public int getBaseline()
    {
        EditText editText = getEditText();
        return editText.getPaddingTop() + editText.getBaseline();
    }
}

I'm assuming PercentRelativeLayout supports baseline aligment. Otherwise you can wrap CTextInputLayout and TextView inside a RelativeLayout to achive a baseline aligment.

3
Tom Howard On

Inside the TextInputLayout, place a RelativeLayout with the EditText and TextView as children:

         <android.support.design.widget.TextInputLayout
                android:id="@+id/textInputLayout_soil_nitrogen"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentLeft="true"
                android:layout_alignParentStart="true"
                android:layout_alignParentTop="true"
                android:layout_widthPercent="63%">

                <RelativeLayout
                    android:layout_width="match_parent"
                    android:layout_height="match_parent">

                    <EditText
                        android:id="@+id/edittext_soil_nitrogen"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:hint="Enter N of soil"
                        android:text="10000" />

                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_alignBaseline="@id/edittext_soil_nitrogen"
                        android:layout_alignParentRight="true"
                        android:layout_widthPercent="37%"
                        android:text="Deficient" />

                </RelativeLayout>

            </android.support.design.widget.TextInputLayout>` 
3
Devenom On

If you are using Kotlin I found a solution that works (Kind of). Its programmatic solution.

I have used a ConstraintLayout to wrap the views

Let's assume textViewDeficient is the view to align to the baseline of the TextInputLayout's layout.

This is how my layout would look

<androidx.constraintlayout.widget.ConstraintLayout
    android:id="@+id/cl_wrapper"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <com.google.android.material.textfield.TextInputLayout
        android:id="@+id/textInputLayout"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:hint="@string/phone_number"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent">

        <com.google.android.material.textfield.TextInputEditText
            android:id="@+id/textInputEditText"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="100000"/>

    </com.google.android.material.textfield.TextInputLayout>

    <TextView
        android:id="@+id/textViewDeficient"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintStart_toEndOf="@id/textInputLayout"
        app:layout_constraintLeft_toRightOf="@id/textInputLayout"
        app:layout_constraintTop_toTopOf="@id/textInputLayout"
        android:text="Deficient"/>

</androidx.constraintlayout.widget.ConstraintLayout>

And in your activity have this method

private fun adjustTextView() {
    fun setTextViewTopMargin() {
        textInputLayout?.post {
            val frameLayout = textInputLayout?.children?.iterator()?.next()
            if (frameLayout is FrameLayout) {
                frameLayout.postIt { fl ->
                    textInputEditText?.postIt { tiet ->
                        val topMargin = fl.marginTop + tiet.marginTop + dpToPx(5)
                        textViewDeficient?.updateLayoutParams<ConstraintLayout.LayoutParams> {
                            updateMargins(top = topMargin)
                        }
                    }
                }
            }
        }
    }

    textInputLayout?.addOnLayoutChangeListener { _, _, _, _, _, _, _, _, _ ->
        setTextViewTopMargin()
    }
    setTextViewTopMargin()
}

Add these extension functions to your activity or any file

fun View.postIt(postAction: (v: View) -> Unit) { post { postAction.invoke(this) }}

fun Context.dpToPx(dp: Int) = TypedValue.applyDimension(
        TypedValue.COMPLEX_UNIT_DIP, dp.toFloat(), resources.displayMetrics
    ).toInt()

Now call

adjustTextView()

in the onCreate method of your activity

I hope this helps. Let me know if it can be improved