Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Align ConstraintLayout item to be at the end of two items

I have a ConstraintLayout with two views A and B that are stacked vertically. I have a third view C which needs to be to the end of both A and B horizontally. At any given point, A may be wider than B or vice versa, so the constraint cannot only be based on one view. Is there a way of defining this constraint through view C?

Currently, I can define A and B so that

app:layout_constraintEnd_toStartOf="C"

This does work, but since there is no start constraint in C, the design preview will not properly draw other properties such as

app:layout_constraintHorizontal_bias="1.0"

Another option may be to somehow group A and B. Most questions on grouping talk about chains, which I don't think resolves this issue. Adding another view to wrap the two also seems to defeat the purpose of a ConstraintLayout, which is meant to eliminate nested children.

Edit: I have an attached an example below:

<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <TextView
        android:id="@+id/view_c"
        android:layout_width="wrap_content"
        android:layout_height="0dp"
        android:layout_marginStart="16dp"
        android:text="View C"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.5" />

    <TextView
        android:id="@+id/view_a"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp"
        android:text="View A"
        app:layout_constraintBottom_toTopOf="@id/view_b"
        app:layout_constraintEnd_toStartOf="@id/view_c"
        app:layout_constraintHorizontal_bias="0"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_goneMarginBottom="16dp" />

    <TextView
        android:id="@+id/view_b"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="16dp"
        android:text="View B"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toStartOf="@id/view_c"
        app:layout_constraintHorizontal_bias="0"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/view_a" />

</android.support.constraint.ConstraintLayout>

In this case, the preview should show "View C" somewhere in the middle since its bias is 0.5. However, it does not know its starting bound as they are defined in view_a and view_b, and therefore sticks to the very right.

Solution:

Below is my final layout in its entirety

<?xml version="1.0" encoding="utf-8"?>

<!--due to animations, we need a wrapper viewgroup so our changes will stick-->

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="?android:attr/selectableItemBackground"
    android:baselineAligned="false"
    android:clipToPadding="false"
    android:minHeight="?android:attr/listPreferredItemHeightSmall"
    android:orientation="horizontal"
    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
    android:paddingStart="?android:attr/listPreferredItemPaddingStart">

    <android.support.constraint.ConstraintLayout
        android:id="@+id/kau_pref_container"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <!--As per Android N, icons (24dp) are aligned to the left rather than centered-->

        <ImageView
            android:id="@+id/kau_pref_icon"
            android:layout_width="56dp"
            android:layout_height="56dp"
            android:layout_marginBottom="4dp"
            android:layout_marginTop="4dp"
            android:contentDescription="@string/kau_pref_icon"
            android:paddingEnd="32dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.5"
            tools:layout_editor_absoluteX="0dp" />

        <TextView
            android:id="@+id/kau_pref_title"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginTop="16dp"
            android:ellipsize="marquee"
            android:textAppearance="?android:attr/textAppearanceListItem"
            android:textColor="?android:attr/textColorPrimary"
            app:layout_constraintBottom_toTopOf="@+id/kau_pref_desc"
            app:layout_constraintEnd_toStartOf="@+id/kau_pref_inner_frame"
            app:layout_constraintHorizontal_bias="0"
            app:layout_constraintStart_toEndOf="@id/kau_pref_icon"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_goneMarginBottom="16dp"
            tools:layout_editor_absoluteX="-175dp" />

        <TextView
            android:id="@id/kau_pref_desc"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginBottom="16dp"
            android:ellipsize="end"
            android:maxLines="10"
            android:textAppearance="?android:attr/textAppearanceListItemSecondary"
            android:textColor="?android:attr/textColorSecondary"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toStartOf="@id/kau_pref_inner_frame"
            app:layout_constraintHorizontal_bias="0"
            app:layout_constraintStart_toEndOf="@id/kau_pref_icon"
            app:layout_constraintTop_toBottomOf="@id/kau_pref_title"
            tools:layout_editor_absoluteX="-175dp" />

        <android.support.constraint.Barrier
            android:id="@+id/kau_pref_barrier"
            android:layout_width="1dp"
            android:layout_height="wrap_content"
            app:constraint_referenced_ids="kau_pref_title,kau_pref_desc"
            app:barrierDirection="end"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintBottom_toBottomOf="parent" />

        <LinearLayout
            android:id="@id/kau_pref_inner_frame"
            android:layout_width="wrap_content"
            android:layout_height="0dp"
            android:gravity="center_vertical|end"
            android:orientation="horizontal"
            android:paddingStart="16dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintHorizontal_bias="1.0"
            app:layout_constraintStart_toEndOf="@id/kau_pref_barrier"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.5"
            tools:layout_editor_absoluteX="1dp" />

    </android.support.constraint.ConstraintLayout>

</LinearLayout>

There is a title and a description, and the inner content must be to the end of both views. I've also tried Group, which is also new in the constraint layout beta, but it doesn't adjust when a children is marked as gone.

Resulting layout

like image 978
Allan W Avatar asked Jun 11 '17 19:06

Allan W


People also ask

How do you set a barrier in constraint layout?

Creating Barriers in XMLThe app:barrierDirection attribute determines the direction of the Barrier - in this case it will be positioned at the end of the referenced Views. The list of referenced Views is a comma separated list of the IDs of other Views within the layout (without the @+id/ qualifier).

Which is better RelativeLayout or ConstraintLayout?

ConstraintLayout has flat view hierarchy unlike other layouts, so does a better performance than relative layout. Yes, this is the biggest advantage of Constraint Layout, the only single layout can handle your UI.

Can we use RelativeLayout inside ConstraintLayout?

Constraints define the relation between two different view elements, and chains can be used dictate the spacing between them. In addition, guidelines can be used to create percentage-based layouts. Most of what can be achieved in LinearLayout and RelativeLayout can be done in ConstraintLayout.


1 Answers

This can be easily achieved using the new Barriers feature.

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

    <TextView
        android:id="@+id/view_c"
        android:layout_width="wrap_content"
        android:layout_height="0dp"
        android:text="View C"
        app:layout_constraintLeft_toRightOf="@+id/barrier1"
        app:layout_constraintTop_toTopOf="parent" />

    <android.support.constraint.Barrier
        android:id="@+id/barrier1"
        android:layout_width="1dp"
        android:layout_height="wrap_content"
        app:barrierDirection="right"
        app:constraint_referenced_ids="view_a, view_b"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/view_a"
        android:layout_width="100dp"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp"
        android:text="View A"
        app:layout_constraintBottom_toTopOf="@id/view_b"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_goneMarginBottom="16dp" />

    <TextView
        android:id="@+id/view_b"
        android:layout_width="200dp"
        android:layout_height="wrap_content"
        android:layout_marginBottom="16dp"
        android:text="View B"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/view_a" />

</android.support.constraint.ConstraintLayout>

How to use Barriers ?

Barriers are like building a HUUUUGE WALL that "protects" the views mentioned in constraint_referenced_ids. So, you have to mention which direction it's "supposed to keep out" which in our case is the right (view_c). Just use the barrierDirection attribute.
Finally, don't forget to make sure that view_c is in the keep out zone (layout_constraintLeft_toRightOf="@+id/barrier1").

As this feature is available only in the 1.1.0 beta1 release of ConstraintLayout, don't forget to add this line to your build.gradle file.

compile 'com.android.support.constraint:constraint-layout:1.1.0-beta1'


Hope this helps!

like image 76
Rami Jemli Avatar answered Oct 29 '22 16:10

Rami Jemli