Move view away from overlapping in ConstraintLayout (minimum constraint)

Viewed 90

On some screens the text and image overlap. In that case I want to move the text upwards.

Image

I place a TextView at a percentage position using a guideline. This is the preferred position of the text. Under it is an image with layout_width="match_parent" and ratio preserved. Depending on the screen aspect ratio, the image will become high enough to overlap with the text. In that case, I want the text to move upwards. So I want a "minimum constraint" of like 8dp between the text and image.

<?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">

    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/guidelineGoldenRatio"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        app:layout_constraintGuide_percent="0.381966" />

    <TextView
        android:id="@+id/text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Keep me from overlapping"
        app:layout_constraintTop_toTopOf="@+id/guidelineGoldenRatio"
        app:layout_constraintBottom_toTopOf="@+id/guidelineGoldenRatio"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent" />

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:adjustViewBounds="true"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:srcCompat="@drawable/ic_supercat_popular" />

</androidx.constraintlayout.widget.ConstraintLayout>
3 Answers

You can use a Barrier widget. Set the barrier's diection to "Top" and set the reference ids to your image and the guideline. (If you can't reference the guideline, constrain a Space widget to the guideline and set the Space widget's id in the referenced ids of the barrier.)

Now constrain the text to the barrier with an 8dp margin. The text will now float with the barrier which will always be 8dp above the higher of the guideline and image.

Based on Cheticamp's answer:

<?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">

    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/guidelineGoldenRatio"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        app:layout_constraintGuide_percent="0.381966" />

    <androidx.constraintlayout.widget.Barrier
        android:id="@+id/barrier"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:barrierDirection="top"
        app:constraint_referenced_ids="imageView, guidelineGoldenRatio" />

    <TextView
        android:id="@+id/text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Keep me from overlapping"
        android:textSize="30dp"
        app:layout_constraintBottom_toTopOf="@+id/barrier"
        app:layout_constraintTop_toTopOf="@+id/barrier"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent" />

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:adjustViewBounds="true"
        android:paddingTop="18dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:srcCompat="@drawable/ic_supercat_popular" />

</androidx.constraintlayout.widget.ConstraintLayout>

Note: the minimum distance between text and image goes into image padding. This padding should also compensate for half text height (when centering text vertically around guideline).

How about binding TextView to the Image, and setting padding simply? The image would be always screen-wide, and having a height that depends on the screen type - but the text would be always 8dp over the image.

    <TextView
            android:id="@+id/text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Keep me from overlapping"
            android:paddingBottom="8dp"
            app:layout_constraintBottom_toTopOf="@+id/guidelineGoldenRatio"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent" />
    
        <ImageView
            android:id="@+id/imageView"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:adjustViewBounds="true"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:srcCompat="@drawable/ic_supercat_popular" />
Related