Reputation: 11
Here is what i want:
I have a GridLayout
inside of a ConstraintLayout
, to which I add multiple rows and columns of custom ImageButtons
(BoardCells
) dynamically.
The ImageButtons display circles using a shape
XML file (code below).
I want the BoardCells to have equal width and height so the shape really is a circle and not an oval. I also want the BoardCells to take as much space as possible on the screen and spread evenly.
Here is what I tried:
I tried a fixed size (in dp) for the BoardCells and setting layout_width of the GridLayout to wrap_content
, but that will only work on different screens that are rather similar and does not use the space optimal. Screenshot of the GridLayout with fixed size BoardCells.
When I dont't set size for the shape and BoardCell then nothing gets displayed at all, doen't matter if GridLayout has match_parent
, wrap_content
or 0dp
.
So I tried to give all BoardCells the same weight inside of the GridLayout like this:
GridLayout.LayoutParams params = new GridLayout.LayoutParams();
params.columnSpec = GridLayout.spec(GridLayout.UNDEFINED, 1f);
params.rowSpec = GridLayout.spec(GridLayout.UNDEFINED, 1f);
this.setLayoutParams(params);
this.setScaleType(ScaleType.CENTER);
But setting column-
and rowSpec
does not keep the ratio so I don't get circles (which makes sense).
Screenshot of the GridLayout with column- and rowSpec set to 1 for every BoardCell.
So I tried to only set columnSpec and setting the ScaleType
to CENTER
or CENTER_INSIDE
, hoping this would keep the ratio but stretch as much as possible.
But this only stretches horizontally and takes the fixed size vertically.
Screenshot of the GridLayout with columnSpec set to 1 and ScaleType CENTER
Then I thought I would implement an onLayoutChangedListener
for the GridLayout, but trying to add children to GridLayout inside of onLayoutChanged
resultet in "requestLayout() improperly called" errors in my log.
My last idea is to first display an empty GridLayout and only when the user presses a button to start the game (the button exists anyways because you may play multiple rounds), and the view is already inflated and displayed, I receive the width and height of GridLayout and calculate the biggest possible size for the BoardCells. But this approach does not seem to be best practise.
Now I don't know what would be the right thing to do. Did I do something wrong or is there any solution that I didn't think of at all? Should I experiment with a bunch of emulated devices and create XML shape files for different screen sizes? Is the dynamic approach okay?
Here is the relevant Code:
XML layout file:
<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:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/wood"
android:padding="10dp"
tools:context=".MainActivity">
<androidx.gridlayout.widget.GridLayout
android:id="@+id/board_cells"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@+id/guideline70"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/guideline8"
android:layout_margin="10dp"/>
</androidx.constraintlayout.widget.ConstraintLayout>
I fill this GridLayout with custom ImageButtons with the following Code:
gridLayoutBoard.setUseDefaultMargins(true);
gridLayoutBoard.setRowCount(10);
gridLayoutBoard.setColumnCount(6);
for (int i = gridLayoutBoard.getRowCount()-1; i >= 0; i--) {
for (int j = 0; j < gridLayoutBoard.getColumnCount(); j++) {
if (j == 0 || j == 5) {
Indikator text= new TextView;
gridLayoutBoard.addView(text);
} else {
BoardCell boardCell = new BoardCell(this);
gridLayoutBoard.addView(boardCell);
}
}
}
The ImageButtons (BoardCells) set their background to this selector:
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<layer-list>
<item android:drawable="@drawable/cell_solid"/>
<item android:drawable="@drawable/cell_gradient"/>
</layer-list>
</item>
</selector>
which uses the following solid shape and a gradient with the same size and shape:
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="@color/grey_cell_dings" />
<size
android:width="30dp"
android:height="30dp"/>
</shape>
Upvotes: 1
Views: 100