Constraint layout barrier not working as expected
W

4

8

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

Wethington answered 22/2, 2022 at 6:42 Comment(6)
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.Dorie
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.0Wethington
I have a solution that I will post as an answer since it may help others.Dorie
@AnkitVerma, thanks for 2.0.0 version. Now it moves <Barrier> when <TextInputLayout> shows error.Defilade
downgrade to v 2.0.4 workedCasablanca
app:layout_constrainedHeight="true" add this in your text views it will work.Gamez
D
13

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.)

Dorie answered 22/2, 2022 at 18:31 Comment(5)
This answer doesn't work as well.Wethington
@AnkitVerma Take a look at the updated answer that now has an example. I would be curious if you get a different result.Dorie
This time your code worked . All it needed was a rebuild.Wethington
Doesn't work for TextInputLayout error and Barrier.Defilade
Instead of suppressing the layout optimization. just add constrained height as true in the elements. app:layout_constrainedHeight="true"Gamez
B
2

Adding

app:layout_constrainedHeight="true"

To views referenced by barrier solved my problem.

Beefwood answered 18/3 at 11:51 Comment(1)
it works for me when I am using with barrier.Ess
T
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>
Tonetic answered 22/2, 2022 at 7:6 Comment(1)
You simply added <Space>, but it doesn't change a behaviour.Defilade
D
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.

Defilade answered 30/1, 2023 at 9:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.