4

I have 2 views and I need a barrier below but the barrier does not work as expected. Here is my layout.

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <TextView
        android:id="@+id/textView15"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="This is a text view"
        app:layout_constraintEnd_toStartOf="@+id/t1"
        android:textSize="20sp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <com.google.android.material.textfield.TextInputLayout
        android:id="@+id/t1"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/textView15"
        app:layout_constraintTop_toTopOf="parent">

        <com.google.android.material.textfield.TextInputEditText
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="This is a demo text to check wrap content"/>

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

    <androidx.constraintlayout.widget.Barrier
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:barrierDirection="bottom"
        app:constraint_referenced_ids="textView15,t1"/>

</androidx.constraintlayout.widget.ConstraintLayout>

Constraint layout preview

The black dotted line is the barrier.

This might be a bug or I am doing it wrong, The result is same in preview and actual device

Ankit Verma
  • 496
  • 5
  • 21
  • 1
    You are doing it right. This seems to be an issue with _ConstraintLayout_ 2.1.3. Version 2.0.4 works if you can drop back. Other versions may be OK, too, but I haven't checked. – Cheticamp Feb 22 '22 at 16:08
  • 1
    I checked with other versions and all the versions have same problem from 2.0.1 onwards.. I had to roll back to version 2.0.0 – Ankit Verma Feb 22 '22 at 17:39
  • I have a solution that I will post as an answer since it may help others. – Cheticamp Feb 22 '22 at 18:28
  • @AnkitVerma, thanks for 2.0.0 version. Now it moves when shows `error`. – CoolMind Jan 29 '23 at 20:46

3 Answers3

11

If you specify

app:layout_optimizationLevel="none"

in the XML for the ConstraintLayout, you will find that the barrier will be placed correctly. I am not sure what setting the optimization level achieves, but it has been an issue recently with barriers. (ConstraintLayout version 2.1.3).

Here is how the layout looks before suppressing optimization. The barrier rises up into the right TextView as noted.

enter image description here

We suppress optimization by stating in the XML with no other changes:

<androidx.constraintlayout.widget.ConstraintLayout 
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layout_optimizationLevel="none"
    xmlns:app="http://schemas.android.com/apk/res-auto">

Now the layout looks like this:

enter image description here

The barrier has dropped below the right TextView where it belongs.

This is with ConstraintLayout version 2.1.3.

implementation 'androidx.constraintlayout:constraintlayout:2.1.3'

(It seems that setting optimization level to anything but standard solves this problem.)

Cheticamp
  • 61,413
  • 10
  • 78
  • 131
0
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <TextView
        android:id="@+id/textView15"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:visibility="visible"
        android:text="This is a text view"
        app:layout_constraintEnd_toStartOf="@+id/t1"
        android:textSize="20sp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <com.google.android.material.textfield.TextInputLayout
        android:id="@+id/t1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:visibility="visible"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/textView15"
        app:layout_constraintTop_toTopOf="parent">

        <com.google.android.material.textfield.TextInputEditText
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="This is a demo text to check wrap content"/>

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

    <androidx.constraintlayout.widget.Barrier
        android:id="@+id/barrier"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:barrierDirection="bottom"
        app:constraint_referenced_ids="textView15,t1"/>
    <Space
       android:id="@+id/space"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:visibility="visible"
       app:layout_constraintStart_toStartOf="parent"
       app:layout_constraintTop_toTopOf="@id/barrier" />
</androidx.constraintlayout.widget.ConstraintLayout>
Thaiyalnayaki
  • 148
  • 1
  • 8
0

As was written before, ConstraintLayout versions 2.1.3 and 2.1.4 work incorrectly, you can downgrade it to 2.0.0. If not, you can use two ways. In both cases remove <androidx.constraintlayout.widget.Barrier>.

  1. Insert LinearLayout to occupy needed views. For instance, if you have 2 TextInputLayouts in horizontal position, you can write so:

     <LinearLayout
         android:id="@+id/layout"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:orientation="horizontal"
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintTop_toBottomOf="@+id/upper_view">
    
         <com.google.android.material.textfield.TextInputLayout
             android:id="@+id/input_layout_1"
             android:layout_weight="1"
             ...
    
    
         <com.google.android.material.textfield.TextInputLayout
             android:id="@+id/input_layout_2"
             android:layout_weight="1"
             ...
     </LinearLayout>
    
  2. If you have a complex layout with different views, write so.

    <Space
         android:id="@+id/space"
         android:layout_width="match_parent"
         android:layout_height="0dp"
         app:layout_constraintBottom_toBottomOf="@id/input_layout_2"
         app:layout_constraintTop_toBottomOf="@+id/upper_view" />
    

    Then you should change Space height in code. Probably you can apply this code to all TextInputLayouts.

     // View size change listener
     private fun View.onSizeChange(callback: () -> Unit) {
         addOnLayoutChangeListener(object : OnLayoutChangeListener {
             override fun onLayoutChange(
                 view: View?,
                 left: Int,
                 top: Int,
                 right: Int,
                 bottom: Int,
                 oldLeft: Int,
                 oldTop: Int,
                 oldRight: Int,
                 oldBottom: Int,
             ) {
                 view?.removeOnLayoutChangeListener(this)
                 if (right - left != oldRight - oldLeft || bottom - top != oldBottom - oldTop) {
                     callback()
                 }
             }
         })
     }
    
     binding.inputLayout2.onSizeChange {
         // First remove bottom constraint
         val layoutParams = binding.space.layoutParams as ConstraintLayout.LayoutParams
         layoutParams.bottomToBottom = ConstraintLayout.LayoutParams.UNSET
         // Now set height of a <Space> (maximum of two TextInputLayouts)
         val h1 = binding.inputLayout1.height
         val h2 = binding.inputLayout2.height
         binding.inputLayout2.postDelayed({
             binding.space.updateLayoutParams { height = max(h1, h2) }
         }, 1)
     }
    

Then bind bottom views to LinearLayout or Space instead of Barrier.

CoolMind
  • 26,736
  • 15
  • 188
  • 224