I'm trying to create a layout draw of a system, which is very similar to a table, therefore, I try to create a constraint layout with rows and columns (which I may need to connect with lines, therefore, vertical/horizontal layouts are not best suited for it).
Also, since the system is of different sizes known only at runtime, I must draw the layout programmatically.
I have a problem with constructing such a ConstraintLayout - even though I have added all elements to the layout, it doesn't render them on the screen.
I'm using Android Pie (API level 28, creating it for very specific devices using it), with Java 8.
I have followed the instructions given in the following articles:
Attaching simplified version of my code (which still doesn't work).
The code does the following:
For each row:
2.1. Creates and adds buttons according to the numbers in the row to the general layout
2.2. Connect the buttons using the general ConstrainSet
2.3. Create a chain out of the buttons in the current row (since I want these to be in the same elevation)
2.4. Connect the buttom number 0 to the previous row (or to the top of the screen, these are the "centers" of each row)
And the code is:
public class MainActivity extends AppCompatActivity {
private final static String logTag = "Main Test";
private final static int NUM_OF_ROWS = 5;
private List<List<Integer>> mLayoutNums;
private ConstraintLayout mScreenLayout;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mScreenLayout = findViewById(R.id.main_layout);
createMockupData();
drawBuildingLayout();
}
private void createMockupData() {
mLayoutNums = new ArrayList<>(NUM_OF_ROWS);
/*
The output should be as follows:
[2, 0, 1, 3]
[0]
[0, 1]
[1, 0, 2, 3, 4]
[0, 1, 2]
*/
mLayoutNums.add(Arrays.asList(0, 1, 2));
mLayoutNums.add(Arrays.asList(1, 0, 2, 3, 4));
mLayoutNums.add(Arrays.asList(0, 1));
mLayoutNums.add(Arrays.asList(0));
mLayoutNums.add(Arrays.asList(2, 0, 1, 3));
}
private void drawBuildingLayout() {
ConstraintSet conSet = new ConstraintSet();
conSet.clone(mScreenLayout);
int[] centerIds = new int[NUM_OF_ROWS];
for (int row = NUM_OF_ROWS - 1; row >= 0; --row) {
List<Integer> numsInRow = mLayoutNums.get(row);
addSingleRow(row, numsInRow, conSet, centerIds);
}
// connect last row to the bottom
conSet.connect(ConstraintSet.PARENT_ID,
ConstraintSet.BOTTOM,
centerIds[0],
ConstraintSet.BOTTOM);
conSet.createVerticalChain(ConstraintSet.PARENT_ID,
ConstraintSet.TOP,
ConstraintSet.PARENT_ID,
ConstraintSet.BOTTOM,
centerIds,
null,
ConstraintSet.CHAIN_SPREAD);
conSet.applyTo(mScreenLayout);
Log.i(logTag, "the screen should be shown now: " + mScreenLayout.isShown());
}
private void addSingleRow(int row,
List<Integer> numsInRow,
ConstraintSet conSet,
int[] centerIds) {
if (numsInRow.size() > 1) {
addMultipleNumsRow(row, numsInRow, conSet, centerIds);
}
else if (numsInRow.size() == 1){
addSingleNumRow(row, numsInRow.get(0), conSet, centerIds);
}
}
private void connectToPrevRow(int row, ConstraintSet conSet, int[] centerIds) {
if (row < NUM_OF_ROWS - 1) {
conSet.connect(centerIds[row + 1],
ConstraintSet.BOTTOM,
centerIds[row],
ConstraintSet.TOP);
} else if (row == NUM_OF_ROWS - 1) {
conSet.connect(ConstraintSet.PARENT_ID,
ConstraintSet.TOP,
centerIds[row],
ConstraintSet.TOP);
}
}
private void connectAndChainRow(int[] rowButtonIds,
ConstraintSet conSet) {
// First button will be attached to the left side of the parent
int leftNeighborId = ConstraintSet.PARENT_ID;
int leftNeighborSide = ConstraintSet.LEFT;
for (int col = 0; col < rowButtonIds.length; ++col) {
conSet.connect(leftNeighborId,
leftNeighborSide,
rowButtonIds[col],
ConstraintSet.LEFT);
leftNeighborId = rowButtonIds[col];
leftNeighborSide = ConstraintSet.RIGHT;
}
// Connecting to the right side of the parent
conSet.connect(leftNeighborId,
leftNeighborSide,
ConstraintSet.PARENT_ID,
ConstraintSet.RIGHT);
conSet.createHorizontalChain(ConstraintSet.PARENT_ID,
ConstraintSet.LEFT,
ConstraintSet.PARENT_ID,
ConstraintSet.RIGHT,
rowButtonIds,
null,
ConstraintSet.CHAIN_SPREAD);
}
private void addMultipleNumsRow(int row,
List<Integer> numsInRow,
ConstraintSet conSet,
int[] centerIds) {
int[] buttonsIds = new int[numsInRow.size()];
for (int pos = 0; pos < numsInRow.size(); ++pos) {
int col = numsInRow.get(pos);
Button button = createButton(row, col);
button.setLayoutParams(new ConstraintLayout.LayoutParams(ConstraintLayout.LayoutParams.WRAP_CONTENT,
ConstraintLayout.LayoutParams.WRAP_CONTENT));
int currButtonId = button.getId();
buttonsIds[pos] = currButtonId;
mScreenLayout.addView(button);
if (pos == 0) {
centerIds[row] = currButtonId;
}
}
connectAndChainRow(buttonsIds, conSet);
connectToPrevRow(row, conSet, centerIds);
Log.i(logTag, "Created constrain chain and buttons for row: "
+ row + " number of columns: "
+ numsInRow.size());
}
private void addSingleNumRow(int row,
int num,
ConstraintSet conSet,
int[] centerIds) {
Button button = createButton(row, num);
button.setLayoutParams(new ConstraintLayout.LayoutParams(ConstraintLayout.LayoutParams.WRAP_CONTENT,
ConstraintLayout.LayoutParams.WRAP_CONTENT));
mScreenLayout.addView(button);
centerIds[row] = button.getId();
conSet.connect(button.getId(), ConstraintSet.LEFT, ConstraintSet.PARENT_ID, ConstraintSet.LEFT);
conSet.connect(button.getId(), ConstraintSet.RIGHT, ConstraintSet.PARENT_ID, ConstraintSet.RIGHT);
connectToPrevRow(row, conSet, centerIds);
}
private Button createButton(int row, int col) {
Button resButton = new Button(this);
resButton.setTextAlignment(Button.TEXT_ALIGNMENT_CENTER);
resButton.setText(String.format("(%d, %d)", row, col));
resButton.setId(View.generateViewId());
return resButton;
}
}
You are cloning the ConstraintSet before adding your views. As a result, the view ids don't appear in the ConstraintSet and can't be connected.
Try moving the following line to after the for loop.
conSet.clone(mScreenLayout);
This probably won't solve all the issues, but it will help get you started.
Btw, if you don't already know about it, the "Layout Inspector" (Tools->Layout Inspector) is a good way to get a look at your layout from an emulator or device.