将 ConstraintLayout 项目对齐到两个项目的末尾

Align ConstraintLayout item to be at the end of two items

我有一个 ConstraintLayout,它有两个垂直堆叠的视图 A 和 B。我有第三个视图 C,它需要水平地到达 A 和 B 的末端。在任何给定点,A 可能比 B 宽,反之亦然,因此约束不能仅基于一个视图。有没有办法通过视图 C 定义此约束?

目前,我可以定义 A 和 B,这样

app:layout_constraintEnd_toStartOf="C"

这确实有效,但由于 C 中没有开始约束,设计预览将无法正确绘制其他属性,例如

app:layout_constraintHorizontal_bias="1.0"

另一种选择可能是以某种方式将 A 和 B 分组。大多数关于分组的问题都与链有关,我认为这不能解决此问题。添加另一个视图来包裹两者似乎也违背了 ConstraintLayout 的目的,它旨在消除嵌套 children.

编辑:我在下面附上了一个示例:

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

在这种情况下,预览应该在中间某处显示 "View C",因为它的偏差为 0.5。但是,它不知道 view_a 和 view_b 中定义的起始边界,因此坚持最右边。

解法:

下面是我最终的完整布局

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

有标题和描述,里面的内容必须到两个视图的末尾。我也尝试过 Group,它在约束布局测试版中也是新的,但是当 children 被标记为消失时它不会调整。

我在我的 IDE 中尝试了这个,我想出了一些代码在运行时动态地完成它

TextView viewa = (TextView) findViewById(R.id.view_a);
TextView viewb = (TextView) findViewById(R.id.view_b);

ConstraintLayout cl = (ConstraintLayout) findViewById(R.id.constraintLayout);
ConstraintSet cs = new ConstraintSet();
cs.clone(cl);
cs.connect(viewb.getWidth() > viewa.getWidth() ? R.id.view_b : R.id.view_a, ConstraintSet.RIGHT, R.id.view_c, ConstraintSet.LEFT);
cs.applyTo(cl);

这最终会稍微弄乱它,因为它会将更宽的视图推出左侧屏幕。也许你可以解决这个问题,因为我目前无法解决。

这可以使用新的 Barriers 功能轻松实现。

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

如何使用障碍?

障碍就像建造一堵 "protects" constraint_referenced_ids 中提到的观点的 HUUUUGE WALL。所以,你必须指出它是 "supposed to keep out" 的方向,在我们的例子中是正确的 (view_c)。只需使用 barrierDirection 属性。
最后,不要忘记确保 view_c 在禁区内 (layout_constraintLeft_toRightOf="@+id/barrier1")。

由于此功能仅在 ConstraintLayout 的 1.1.0 beta1 版本中可用,请不要忘记将此行添加到您的 build.gradle 文件中。

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


希望这对您有所帮助!