尝试使用 ConstraintLayout 复制 GridLayout 列对齐

Trying to replicate GridLayout column alignment with ConstraintLayout

我是 ConstraintLayout 的新手,我正在尝试使用 ConstraintLayout 复制 GridLayout 提供的相同网格行为。

具体来说,我想设计一个两列的网格。第一列宽度应尽可能窄,而第二​​列应占据所有剩余的水平 space。当然,第二列应该就在第一列的右边,或者更确切地说,在第一列的最宽视图。

我不知道如何使用 ConstraintLayout 复制最后一个要求。我不想在两列之间使用网格线,因为第一列不应具有固定宽度或百分比宽度,而应与其视图的最宽宽度一样宽。

https://gist.github.com/venator85/499dd82f47b3efbbed7a1e9e1ca1412d 我准备了一个布局示例和相应的预览,显示了实现我想要的内容的 GridLayout。该布局中的前两个 ConstraintLayout 尝试显示 C1 和 D1 与 B1 对齐,C2 和 D2 与 B2 对齐。当B2比A2窄时,A1和C1会重叠

有什么帮助吗?

谢谢

更新:请参阅

我怀疑是否有一种方法可以完全按照 XML 的方式用 ConstraintLayout 复制 GridLayout。如果您愿意让一些代码协助布局,那么您可以使用可移动的垂直参考线将 ConstraintLayout 设置为 GridLayout

按照您描述的那样在两列中构建 XML 布局。左栏中每个TextView的顶部将被限制在右栏中相应TextView的顶部,因此左侧条目将随着右侧条目的增加或减少而上下浮动身高。

所有右侧的列视图都将被限制在左侧,以符合上述垂直准则。此指南在 XML 中的放置应该是合理的,但实际放置将在代码中进行,并将根据左侧最宽视图的宽度进行调整。

这是您提出的问题的解决方案,但不是通用解决方案。以下取决于左边每个TextView的高度小于或等于右边对应TextView的高度。

这是 Android Studio 布局编辑器中的布局。我把指南推到右边来演示它是如何浮动的。 (代码跟随图像。)

这是一个屏幕截图。我希望你觉得这很有用。

这里是使用 ConstraintLayout 的布局。 (自初始 post 开始更新,以便在左栏中右转。)

constrained.xml

<?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"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/constrained"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.constraint.Guideline
        android:id="@+id/guideline"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:layout_constraintGuide_begin="257dp" />

    <TextView
        android:id="@+id/L1"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginTop="0dp"
        android:text="A1 A1 A1 A1 A1*"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toLeftOf="@id/guideline"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintWidth_default="wrap"
        tools:ignore="HardcodedText" />

    <TextView
        android:id="@+id/L2"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginLeft="0dp"
        android:layout_marginTop="0dp"
        android:text="B1 B1 B1 B1 B1*"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toLeftOf="@id/guideline"
        app:layout_constraintTop_toTopOf="@+id/R2"
        app:layout_constraintWidth_default="wrap"
        tools:ignore="HardcodedText" />

    <TextView
        android:id="@+id/L3"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginLeft="0dp"
        android:layout_marginTop="0dp"
        android:text="A2 A2 A2 A2*"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toLeftOf="@id/guideline"
        app:layout_constraintTop_toTopOf="@+id/R3"
        app:layout_constraintWidth_default="wrap"
        tools:ignore="HardcodedText" />

    <TextView
        android:id="@+id/L4"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginLeft="0dp"
        android:layout_marginTop="0dp"
        android:text="B2 B2 B2 B2 B2*"
        app:layout_constraintHorizontal_bias="0.02"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toLeftOf="@id/guideline"
        app:layout_constraintTop_toTopOf="@+id/R4"
        app:layout_constraintWidth_default="wrap"
        tools:ignore="HardcodedText" />

    <TextView
        android:id="@+id/R1"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="C1 C1 C1 C1 C1 C1 C1 C1 C1 C1 C1 C1 C1 C1 C1 C1 C1 C1 C1 C1 C1 C1*"
        app:layout_constraintLeft_toRightOf="@id/guideline"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:ignore="HardcodedText" />

    <TextView
        android:id="@+id/R2"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="D1 D1 D1 D1 D1 D1 D1 D1 D1 D1 D1 D1 D1 D1 D1 D1 D1 D1 D1 D1 D1 D1*"
        app:layout_constraintLeft_toRightOf="@+id/guideline"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/R1"
        tools:ignore="HardcodedText" />

    <TextView
        android:id="@+id/R3"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="C2 C2 C2 C2 C2 C2 C2 C2 C2 C2 C2 C2 C2 C2 C2 C2 C2 C2 C2 C2 C2 C2*"
        app:layout_constraintLeft_toRightOf="@id/guideline"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@id/R2"
        tools:ignore="HardcodedText" />

    <TextView
        android:id="@+id/R4"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="D2 D2 D2 D2 D2 D2 D2 D2 D2 D2 D2 D2 D2 D2 D2 D2 D2 D2 D2 D2 D2 D2*"
        app:layout_constraintLeft_toRightOf="@+id/guideline"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/R3"
        tools:ignore="HardcodedText" />

</android.support.constraint.ConstraintLayout>

这里是调整引导线位置的Activity

MainActivity.java

package com.example.layout2;

import android.os.Bundle;
import android.support.constraint.ConstraintLayout;
import android.support.constraint.Guideline;
import android.support.v7.app.AppCompatActivity;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    private Guideline mGuideline;
    private ConstraintLayout mConstraintLayout;
    private TextView L1;
    private TextView L2;
    private TextView L3;
    private TextView L4;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.constrained);
        mConstraintLayout = (ConstraintLayout) findViewById(R.id.constrained);
        mGuideline = (Guideline) findViewById(R.id.guideline);
        L1 = (TextView) findViewById(R.id.L1);
        L2 = (TextView) findViewById(R.id.L2);
        L3 = (TextView) findViewById(R.id.L3);
        L4 = (TextView) findViewById(R.id.L4);
        // We will adjust the location of the guideline after layout is completed.
        mConstraintLayout.post(new Runnable() {
            @Override
            public void run() {
                moveGuideline();
            }
        });
    }

    public void moveGuideline() {
        ConstraintLayout.LayoutParams params;

        params = (ConstraintLayout.LayoutParams) mGuideline.getLayoutParams();
        // Find the widest TextView in the left column...
        params.guideBegin = Math.max(Math.max(L1.getWidth(), L2.getWidth()),
                Math.max(L3.getWidth(), L4.getWidth()));
        // ... and set the guideline to the right of the widest one.
        mGuideline.setLayoutParams(params);
    }
}

试试这个。

<?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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">


    <TextView
        android:id="@+id/textView5"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginLeft="8dp"
        android:layout_marginTop="8dp"
        android:text="A1 A1 A1 A1 "
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/textView8"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginLeft="8dp"
        android:layout_marginRight="8dp"
        android:layout_marginTop="8dp"
        android:text="C1 C1 C1 C1 "
        app:layout_constraintHorizontal_bias="0.506"
        app:layout_constraintLeft_toRightOf="@+id/textView5"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/textView9"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginLeft="8dp"
        android:layout_marginRight="8dp"
        android:layout_marginTop="8dp"
        android:text="B1 B1 B1 B1 "
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toLeftOf="@+id/textView8"
        app:layout_constraintTop_toBottomOf="@+id/textView8" />

    <TextView
        android:id="@+id/textView10"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginLeft="8dp"
        android:layout_marginRight="8dp"
        android:layout_marginTop="8dp"
        android:text="D1 D1 D1 D1 "
        app:layout_constraintHorizontal_bias="0.506"
        app:layout_constraintLeft_toRightOf="@+id/textView5"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textView5" />

</android.support.constraint.ConstraintLayout>

像这样。

更新

接受的答案是正确的。当我在 2017 年 3 月回答这个问题时,这是唯一的选择。两个月后,Google 引入了障碍。


我认为目前不可能只用一个 ConstraintLayout 容器来执行。我希望将来 Google 会添加类似 group_id 的内容或其他一些计算布局的方式“对齐到组”。

同时,我建议您在 ConstraintLayout 中使用 ConstraintLayout 个容器。 我是这样实现的:

为了使行像“网格”一样,我使用了“”。每个 ConstraintLayout 链中的行数必须相同,因此自动分配将正确对齐行。 (尽管如果不使用它们可以留空或隐藏)。

xml gist

Google 在 ConstraintLayout 的最新版本中引入了 "barriers" 的想法,这有助于在 XML 中 100% 解决这个问题。请参阅涉及新内容的 ConstraintLayout 1.1.0 beta 1 release notes . Although, that note doesn't contain a lot of information on the new capabilities there was a talk at I/O 2017

新的解决方案是用障碍复制 GridLayout 的网格。在左侧 TextView 的右侧放置了一个垂直屏障,在前三行下方放置了一个屏障。障碍根据每个 TextView 中存在的文本数量而变化,但始终保持 app:constraint_referenced_ids 中指定的位置。从本质上讲,障碍就像浮动指南。此解决方案不依赖任何编码来支持视频中的内容。

这是一个 video of the new layout,它显示了每个 TextView 在另一个 TextView 的内容发生变化时所需要的定位。该视频是使用 Android Studio 2.3.2 的设计工具制作的。

和 XML 使用障碍的新布局:

<?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"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/constrained"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.constraint.Barrier
        android:id="@+id/barrierVertical"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:orientation="vertical"
        app:barrierDirection="right"
        app:constraint_referenced_ids="L1, L2, L3, L4" />

    <TextView
        android:id="@+id/L1"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_margin="8dp"
        android:text="L1 *"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:ignore="HardcodedText" />

    <TextView
        android:id="@+id/R1"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_margin="8dp"
        android:text="R1 R1 R1 R1 R1 R1 R1 R1 R1 R1 R1 R1 R1 R1 R1 R1 R1 R1 R1 R1 R1 R1 R1 R1*"
        app:layout_constraintLeft_toRightOf="@+id/barrierVertical"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:ignore="HardcodedText" />

    <android.support.constraint.Barrier
        android:id="@+id/barrier1"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:orientation="horizontal"
        app:barrierDirection="bottom"
        app:constraint_referenced_ids="L1, R1" />

    <TextView
        android:id="@+id/L2"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_margin="8dp"
        android:text="L2 L2*"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toBottomOf="@id/barrier1"
        tools:ignore="HardcodedText" />

    <TextView
        android:id="@+id/R2"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_margin="8dp"
        android:text="R2 R2 R2 R2 R2 R2 R2 R2 R2 R2 R2 R2 R2 R2 R2 R2 R2 R2 R2 R2 R2 R2 R2*"
        app:layout_constraintLeft_toRightOf="@+id/barrierVertical"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@id/barrier1"
        tools:ignore="HardcodedText" />

    <android.support.constraint.Barrier
        android:id="@+id/barrier2"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:orientation="horizontal"
        app:barrierDirection="bottom"
        app:constraint_referenced_ids="L2, R2" />

    <TextView
        android:id="@+id/L3"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_margin="8dp"
        android:text="L3 L3 L3*"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toBottomOf="@id/barrier2"
        tools:ignore="HardcodedText" />

    <TextView
        android:id="@+id/R3"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_margin="8dp"
        android:text="R3 R3 R3 R3 R3 R3 R3 R3 R3 R3 R3 R3 R3 R3 R3 R3 R3 R3 R3 R3 R3 R3*"
        app:layout_constraintLeft_toRightOf="@id/barrierVertical"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@id/barrier2"
        tools:ignore="HardcodedText" />

    <android.support.constraint.Barrier
        android:id="@+id/barrier3"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:orientation="horizontal"
        app:barrierDirection="bottom"
        app:constraint_referenced_ids="L3, R3" />

    <TextView
        android:id="@+id/L4"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_margin="8dp"
        android:text="L4 L4 L4 L4 L4 L4*"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/barrier3"
        tools:ignore="HardcodedText,RtlHardcoded" />

    <TextView
        android:id="@+id/R4"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_margin="8dp"
        android:text="R4 R4 R4 R4 R4 R4 R4 R4 R4 R4 R4 R4 R4 R4 R4 R4 R4 R4 R4 R4 R4*"
        app:layout_constraintLeft_toRightOf="@+id/barrierVertical"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/barrier3"
        tools:ignore="HardcodedText" />

</android.support.constraint.ConstraintLayout>