Reputation: 163
I want to create a square grid inside ConstraintLayout
. My first thought was to create a horizontal chain, give some margin value and set to all single view size attributes width = match_constraint
, height = match_constraint
and set the ratio to 1:1. It works and it looks like:
And it's easy when a size of the grid is 2×2 - there are 4 elements so it's easy. But what I should do when I had to create a grid 7×7? We have 49 views so setting all of these views could be tricky. I want to do this in constraint layout because I want to have a flexible layout. :)
Upvotes: 6
Views: 3999
Reputation: 723
I liked @cheticamp's answer so much, that I was curious how this would look like in xml, in case you don't want to do it programmatically, because this might make it easier to adjust and see a preview if you have mostly static content.
Hence I tried it out and here I would like to share the code with you. Note, that for the sake of simplicity I will only show a 3x3 grid...
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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/layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
tools:context=".ui.grid">
<Space
android:id="@+id/grid_frame"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.5" />
<!-- ROW 0 -->
<TextView
android:id="@+id/tile_00"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="1"
android:background="#F44336"
android:gravity="center"
android:text="1"
android:textSize="24sp"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintEnd_toStartOf="@id/tile_01"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="@id/grid_frame"
app:layout_constraintTop_toTopOf="@id/grid_frame" />
<TextView
android:id="@+id/tile_01"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="1"
android:background="#03A9F4"
android:gravity="center"
android:text="2"
android:textSize="24sp"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintEnd_toStartOf="@id/tile_02"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@id/tile_00"
app:layout_constraintTop_toTopOf="@id/grid_frame" />
<TextView
android:id="@+id/tile_02"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="1"
android:background="#F44336"
android:gravity="center"
android:text="3"
android:textSize="24sp"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintEnd_toEndOf="@id/grid_frame"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@id/tile_01"
app:layout_constraintTop_toTopOf="@id/grid_frame" />
<!-- ROW 1 -->
<TextView
android:id="@+id/tile_10"
layout="@layout/fragment_tile"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="1"
android:background="#03A9F4"
android:gravity="center"
android:text="4"
android:textSize="24sp"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintEnd_toStartOf="@id/tile_11"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintHorizontal_chainStyle="spread"
app:layout_constraintStart_toStartOf="@id/grid_frame"
app:layout_constraintTop_toBottomOf="@id/tile_00" />
<TextView
android:id="@+id/tile_11"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="1"
android:background="#F44336"
android:gravity="center"
android:text="5"
android:textSize="24sp"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintEnd_toStartOf="@id/tile_12"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@id/tile_10"
app:layout_constraintTop_toBottomOf="@id/tile_01" />
<TextView
android:id="@+id/tile_12"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="1"
android:background="#03A9F4"
android:gravity="center"
android:text="6"
android:textSize="24sp"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintEnd_toEndOf="@id/grid_frame"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@id/tile_11"
app:layout_constraintTop_toBottomOf="@id/tile_02" />
<!-- ROW 2 -->
<TextView
android:id="@+id/tile_20"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="1"
android:background="#F44336"
android:gravity="center"
android:text="7"
android:textSize="24sp"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintEnd_toStartOf="@id/tile_21"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintHorizontal_chainStyle="spread"
app:layout_constraintStart_toStartOf="@id/grid_frame"
app:layout_constraintTop_toBottomOf="@id/tile_10" />
<TextView
android:id="@+id/tile_21"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="1"
android:background="#03A9F4"
android:gravity="center"
android:text="8"
android:textSize="24sp"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintEnd_toStartOf="@id/tile_22"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@id/tile_20"
app:layout_constraintTop_toBottomOf="@id/tile_11" />
<TextView
android:id="@+id/tile_22"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="1"
android:background="#F44336"
android:gravity="center"
android:text="9"
android:textSize="24sp"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintEnd_toEndOf="@id/grid_frame"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@id/tile_21"
app:layout_constraintTop_toBottomOf="@id/tile_12" />
</androidx.constraintlayout.widget.ConstraintLayout>
... resulting in...
Notes:
Upvotes: 0
Reputation: 921
If I got it right I think the best way is to use the Flow widget
androidx.constraintlayout.helper.widget.Flow
and put the id of all views which should be included in the grid in the following field:
app:constraint_referenced_ids
more info can be found here:
https://bignerdranch.com/blog/constraintlayout-flow-simple-grid-building-without-nested-layouts/
Upvotes: 0
Reputation: 62831
Since you say that you have a variable number of squares, I assume that you are willing to create the n*n grid in code. Here is an approach to creating the grid. This is just one way and there are probably others.
First, create a layout with ConstraintLayout
as the root view. In that layout, define a widget that has width and height of match_constraints
and is constrained by the parent. This will give you a square widget regardless of the device orientation. (I use a View
here so it can be seen, but it is better to use a Space
widget although it probably doesn't really matter.)
activity_main.xml
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<View
android:id="@+id/gridFrame"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_margin="16dp"
android:background="@android:color/holo_blue_light"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
Here is the code for the activity that creates a 7*7 grid. We will use the on-screen view from the layout as the "parent" view to contain the squares.
MainActivity.java
public class MainActivity extends AppCompatActivity {
int mRows = 7;
int mCols = 7;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ConstraintLayout layout = findViewById(R.id.layout);
int color1 = getResources().getColor(android.R.color.holo_red_light);
int color2 = getResources().getColor(android.R.color.holo_blue_light);
TextView textView;
ConstraintLayout.LayoutParams lp;
int id;
int idArray[][] = new int[mRows][mCols];
ConstraintSet cs = new ConstraintSet();
// Add our views to the ConstraintLayout.
for (int iRow = 0; iRow < mRows; iRow++) {
for (int iCol = 0; iCol < mCols; iCol++) {
textView = new TextView(this);
lp = new ConstraintLayout.LayoutParams(ConstraintSet.MATCH_CONSTRAINT,
ConstraintSet.MATCH_CONSTRAINT);
id = View.generateViewId();
idArray[iRow][iCol] = id;
textView.setId(id);
textView.setText(String.valueOf(id));
textView.setGravity(Gravity.CENTER);
textView.setBackgroundColor(((iRow + iCol) % 2 == 0) ? color1 : color2);
layout.addView(textView, lp);
}
}
// Create horizontal chain for each row and set the 1:1 dimensions.
// but first make sure the layout frame has the right ratio set.
cs.clone(layout);
cs.setDimensionRatio(R.id.gridFrame, mCols + ":" + mRows);
for (int iRow = 0; iRow < mRows; iRow++) {
for (int iCol = 0; iCol < mCols; iCol++) {
id = idArray[iRow][iCol];
cs.setDimensionRatio(id, "1:1");
if (iRow == 0) {
// Connect the top row to the top of the frame.
cs.connect(id, ConstraintSet.TOP, R.id.gridFrame, ConstraintSet.TOP);
} else {
// Connect top to bottom of row above.
cs.connect(id, ConstraintSet.TOP, idArray[iRow - 1][0], ConstraintSet.BOTTOM);
}
}
// Create a horiontal chain that will determine the dimensions of our squares.
// Could also be createHorizontalChainRtl() with START/END.
cs.createHorizontalChain(R.id.gridFrame, ConstraintSet.LEFT,
R.id.gridFrame, ConstraintSet.RIGHT,
idArray[iRow], null, ConstraintSet.CHAIN_PACKED);
}
cs.applyTo(layout);
}
}
Just change mRows
and mCols
and the grid will adjust itself. If your grid will always be square, you will not need to set the ratio of the grid container in the code. You can also place your grid within a more complicated layout. Just make sure that the grid container has the right dimensions and you are good to go.
Upvotes: 8
Reputation: 389
Best idea is to create two views linear layouts, one that has horizontalAlignment and Another that has vertical alignment. Group with vertical alignment is one that you call in your layout and pass to it as an attribute a number(7). This group will add horizontal group 7 times to itself. Each horizontal layout will in-turn take a number (7) again. And that will add 7 squares. Trick is to see that each square will have same weight. And each horizontal row will have same weight. That way u will get grids of right size provides you insert Verical layout in square ViewGroup
Upvotes: 0