Search code examples
android-layoutandroid-constraintlayout

Handling GONE views puzzle in ConstraintLayout


I have a simple enough looking layout with what turns out to be quite a tricky behaviour to accomplish using xml alone i.e. using only the features of ConstraintLayout and not having to do anything programmatically.

I have considered Barriers & Guidlines and many scenarios and trials with no success; so this is my last hope that maybe someone else knows something I don't.

Here is my puzzle:

  • If 3 lines visible -> image should be centred between line 1 and line 2
  • If 2 lines visible -> image should be centred between line 1 and line 2
  • If 1 line visible (label_text) -> image should be centred in parent, or centre aligned with line 1 (label_text)

Here are some images to illustrate:

3 Lines - correct

3 Lines

2 Lines - correct

2 Lines

1 Line incorrect but best I can get so far [when only Label is visible] 1 Line incorrect but best I can get so far

1 Line correct the way I want it to be [when only Label is visible] 1 Line correct the way I want it to be

Code:

<androidx.constraintlayout.widget.ConstraintLayout
    style="@style/V2.ItemList.Background"
    android:minHeight="@dimen/item_minimum_height"
    android:paddingVertical="@dimen/=margin_vertical">

    <ImageView
        android:id="@+id/icon"
        app:layout_constraintBottom_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="parent"
        tools:src="@drawable/ic_img"
        tools:visibility="visible" />

    <TextView
        android:id="@+id/label_text"
        app:layout_constraintBottom_toTopOf="@id/line1_text"
        app:layout_constraintEnd_toStartOf="@id/right_content"
        app:layout_constraintStart_toEndOf="@id/icon_start"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_chainStyle="packed"
        tools:text="Label" />

    <TextView
        android:id="@+id/line1_text"
        android:layout_marginTop="4dp"
        app:layout_constraintBottom_toTopOf="@id/line2_text"
        app:layout_constraintEnd_toStartOf="@id/right_content"
        app:layout_constraintStart_toEndOf="@id/icon"
        app:layout_constraintTop_toBottomOf="@id/label_text"
        tools:text="Line 1"
        tools:visibility="gone" />

    <TextView
        android:id="@+id/line2_text"
        android:layout_marginTop="4dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toStartOf="@id/right_content"
        app:layout_constraintStart_toEndOf="@id/icon"
        app:layout_constraintTop_toBottomOf="@id/line1_text"
        tools:text="Line 2"
        tools:visibility="gone" />

</androidx.constraintlayout.widget.ConstraintLayout>

Any help is much appreciated!

UPDATE

See Cheticamp's answer below which is best solution but in case it's useful for anyone else here's the way I was going to do it programmatically if I couldn't find an xml only solution:

private fun adjustConstraints() {
    if(binding.line1Text.isGone && binding.line1Text.isGone) {
        ConstraintSet().apply {
            clone(binding.itemListLayout)
            // Adjust left/start content for single line
            connect(
                R.id.icon,
                ConstraintSet.TOP,
                R.id.item_list_layout,
                ConstraintSet.TOP
            )
            connect(
                R.id.icon,
                ConstraintSet.BOTTOM,
                R.id.item_list_layout,
                ConstraintSet.BOTTOM
            )
            // Adjust right/end content for single line
            connect(
                R.id.right_content,
                ConstraintSet.TOP,
                R.id.item_list_layout,
                ConstraintSet.TOP
            )
            connect(
                R.id.right_content,
                ConstraintSet.BOTTOM,
                R.id.item_list_layout,
                ConstraintSet.BOTTOM
            )
        }.also {
            it.applyTo(binding.itemListLayout)
        }
    }
}

Solution

  • Constrain the ImageView to the top of label_text and to the bottom of line_1_text.

    <ImageView
        android:id="@+id/icon"
        app:layout_constraintTop_toTopOf="@id/label_text"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintBottom_toBottomOf="@id/line1_text"
        tools:src="@drawable/ic_img"
        tools:visibility="visible" />