Trying to replicate GridLayout column alignment with ConstraintLayout

谁说我不能喝 提交于 2019-12-03 05:55:35

Google has introduced the idea of "barriers" in the latest release of ConstraintLayout that helps to make an answer to this question 100% solvable in XML. See the 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 that touched on the new stuff.

The new solution is to replicate the grid of GridLayout with barriers. There is a vertical barrier placed to the right of the left-hand TextViews and a barrier under the top three rows. The barriers shift depending upon how much text is present in each TextView but always maintain the position specified in app:constraint_referenced_ids. In essence, barriers act like floating guidelines. This solution is not relying upon any coding to support what is in the video.

Here is a video of the new layout that shows the desired positioning each TextView being maintained as the contents of another TextView changes. The video was made in the design tools of Android Studio 2.3.2.

And XML for the new layout using 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"
    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>

Try this out.

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

Something like this.

Update : See the accepted answer.

I doubt that there is a way to replicate a GridLayout with a ConstraintLayout in the way that you want purely with XML. If you are willing to let a little code assist the layout, then you can set up the ConstraintLayout to work as a GridLayout using a movable vertical guideline.

Build the XML layout in two columns as you depict. The top of each TextView in the left column will be constrained to the top of the corresponding TextView in the right column, so the left entries will float up or down as the entries on the right increase or decrease in height.

All right column views will be constrained on the left to the vertical guideline mentioned above. The placement of this guideline in the XML should be something reasonable to work with but the actual placement will be made in code and will be adjusted depending upon the width of the widest view on the left.

This is a solution to the problem that you pose but it is not a general solution. The following depends on the height of each TextView on the left being less than or equal to the height of the corresponding TextView on the right.

Here is what the layout looks like in the Android Studio layout editor. I pushed the guideline over to the right to demonstrate how it floats. (Code follows images.)

Here is a screen shot. I hope that you find this useful.

Here is the layout using ConstraintLayout. (Updated since initial post to get wrapping right in left column.)

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>

Here is the Activity that adjusts the location of the guideline.

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);
    }
}
Amir Uval

I don't think it is possible to perform purely with one ConstraintLayout container at this time. I hope that in the future Google will add something like group_id or some other way to calculate layout with "align to group".

In the mean time, I suggest you use ConstraintLayout containers inside ConstraintLayout. This is how I implemented this:

To make the rows "grid" like, I used "ConstraintLayout Chains". Number of rows in each ConstraintLayout chain must be identical, so the auto distribution will align rows correctly. (Though they can stay empty or hidden if not used).

The xml gist

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!