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.
This can be easily achieved using the new
Barriers
feature.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 thebarrierDirection
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.
Hope this helps!
I tried this out in my IDE and i came up with some code to do it dynamically at runtime
This ends up messing it in a slight way as it pushes the view which is wider out of the screen on the left. Maybe you could figure that out as i am unable to at this point.