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