【问题标题】:Trying to replicate GridLayout column alignment with ConstraintLayout尝试使用 ConstraintLayout 复制 GridLayout 列对齐
【发布时间】:2017-08-08 08:18:59
【问题描述】:

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

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

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

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

有什么帮助吗?

谢谢

【问题讨论】:

  • 每个textview的内容是动态的,还是固定长度的?
  • 所有textviews的内容都是动态的。
  • 切换到 CoordinatorLayout 有(好的)理由吗?您的布局是一个网格/表格,并且您已经有了一个很好的小部件来以 GridLayout 的形式构建布局。我认为您不能使用具有基于视图的约束的小部件来复制 GridLayout 默认提供的动态网格。

标签: android android-layout android-gridlayout android-constraintlayout


【解决方案1】:

Google 在最新版本的ConstraintLayout 中引入了“障碍”的概念,有助于100% 地在XML 中解决这个问题。请参阅ConstraintLayout 1.1.0 beta 1 release notes 。尽管该注释没有包含有关新功能的大量信息,但 talk at I/O 2017 涉及到新功能。

新的解决方案是使用障碍复制GridLayout 的网格。左侧TextViews 右侧有一个垂直屏障,前三行下方有一个屏障。障碍会根据每个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>

【讨论】:

  • 但这如何与 ConstraintLayout 上的 wrap_content 一起工作?
【解决方案2】:

更新:见accepted answer

我怀疑是否有一种方法可以像您希望纯粹使用 XML 一样复制 GridLayoutConstraintLayout。如果您愿意让一些代码辅助布局,那么您可以使用可移动的垂直引导线将ConstraintLayout 设置为GridLayout

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

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

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

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

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

这是使用ConstraintLayout 的布局。 (自最初发布以来已更新,以便在左列中自动换行。)

约束.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);
    }
}

【讨论】:

    【解决方案3】:

    试试这个。

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

    类似的东西。

    【讨论】:

      【解决方案4】:

      更新

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


      我认为目前无法仅使用一个ConstraintLayout 容器来执行。我希望将来谷歌会添加类似group_id 或其他方式来计算“对齐组”的布局。

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

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

      xml gist

      【讨论】:

      • 不要在另一个约束布局中使用约束布局。它打破了约束布局的整个概念。
      • @P1NG2WIN 今天你是对的。 3 月 17 日,这是唯一的选择。接受的答案是正确的,但比我晚了 3 个月,比 Google 引入了障碍晚了 1 个月。
      猜你喜欢
      • 2018-02-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-02
      • 2013-10-06
      • 1970-01-01
      • 2017-04-23
      相关资源
      最近更新 更多