12

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.

Community
  • 1
  • 1
Aditya Naique
  • 1,120
  • 13
  • 25

5 Answers5

12

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.

Jona
  • 13,325
  • 15
  • 86
  • 129
3

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>` 
Tom Howard
  • 4,672
  • 2
  • 43
  • 48
  • This Helped me. Thanks! – Yesha May 01 '18 at 06:08
  • 1
    This is ok if you don't mind that the hint and error are shown around the RelativeLayout – shredder Jan 03 '19 at 05:01
  • I agree with @shredder. Also any decorations that are defined in the TextInputLayout won't filter down if you are using `com.google.android.material.textfield.TextInputLayout` surrounding a `com.google.android.material.textfield.TextInputEditText`. Sigh. – SMBiggs Aug 27 '21 at 18:47
2

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%" />

Hitesh KR
  • 21
  • 3
  • Close, but no cigar! This doesn't really guarantee that the baselines line up. In all the cases I tested it looked close, but just off to be noticeable. – SMBiggs Aug 27 '21 at 14:41
1

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

  • 3
    No, this way the baseline of textView is on the same level as editText's line (the purple one in the above picture), which is not what I want. **I want to align the baselines of both of them.** I think this is not possible since the TextView is inside a TextInputLayout. Guess I'll have to just settle with adding a top padding of 20dp. I hope somebody here knows how to achieve that. Thanks for your answer though. Good day to you. :) – Aditya Naique Sep 22 '15 at 08:34
  • ok means you want to same bottom baseline of edittext and textview with base on text. I think for that you need to define same font size and also give bottom padding of textview. It's works. –  Sep 22 '15 at 08:44
  • yep, giving padding is the only way to make this possible it seems. – Aditya Naique Sep 22 '15 at 09:20
0

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

Devenom
  • 915
  • 1
  • 9
  • 20
  • Hmm, your code doesn't compile. The call `dpToPx(5)` can't find the function `Context.dpToPx(dp: Int)`. If I take away the `Context.` it does compile, but I'm not sure that's what you want nor how this will affect the working of your code. Could you explain? – SMBiggs Aug 27 '21 at 19:07
  • 1
    Hi, Context is used for the resources.displayMertics part above in the extension function. The placement of the Context.dpToPX(dp: Int) is important. I would suggest you place these functions in an empty kotlin file. resources.displayMetrics would not run without Context so it is basically Context.resources.displayMetrics – Devenom Aug 27 '21 at 21:48
  • 1
    I'm guessing you placed the dpToPx function within an activity or fragment. Activities/fragments have Context within their scopes. So you would not need the prefix Context to the method. But if you want to use it on a larger scale rather than just one activity/fragment you could leave the Context prefix and place the extension function in any file (but not within any class) – Devenom Aug 27 '21 at 21:54