Как равномерно распределить дочерние элементы, отображающие XML-форму в сетке (с максимально возможным размером)?

#android #android-gridlayout #android-imagebutton #android-shape

Вопрос:

Вот чего я хочу:

У меня есть GridLayout внутри a ConstraintLayout , к которому я динамически добавляю несколько строк и столбцов custom ImageButtons ( BoardCells ). Кнопки изображений отображают круги, используя shape XML-файл (код ниже).

Я хочу, чтобы ячейки доски имели одинаковую ширину и высоту, чтобы форма действительно была кругом, а не овалом. Я также хочу, чтобы настольные ячейки занимали как можно больше места на экране и распределялись равномерно.

Вот что я попробовал:

Я попробовал установить фиксированный размер (в dp) для ячеек платы и установить значение layout_width для сетки wrap_content , но это будет работать только на разных экранах, которые довольно похожи и не используют оптимальное пространство. Снимок экрана сетки с ячейками доски фиксированного размера.

Когда я не задаю размер для фигуры и ячейки доски, тогда вообще ничего не отображается , не имеет значения, есть ли у GridLayout match_parent wrap_content или 0dp .

Поэтому я попытался придать всем доскам одинаковый вес внутри сетки, как это:

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

Но установка column- и rowSpec не сохраняет соотношение, поэтому я не получаю кругов (что имеет смысл).
Снимок экрана сетки с параметрами столбцов и строк, равными 1 для каждой ячейки платы.

Поэтому я попытался установить только columnSpec и установить ScaleType CENTER значение «или CENTER_INSIDE «, надеясь, что это сохранит соотношение, но растянется как можно больше. Но это растягивается только по горизонтали и принимает фиксированный размер по вертикали. Снимок экрана сетки с параметром columnSpec, равным 1, и ЦЕНТРОМ масштабирования

Затем я подумал, что я бы реализовал onLayoutChangedListener для GridLayout, но пытался добавить дочерние элементы в GridLayout внутри набора onLayoutChanged результатов в «неправильно вызванных ошибках requestLayout ()» в моем журнале.

Моя последняя идея состоит в том, чтобы сначала отобразить пустую сетку, и только когда пользователь нажимает кнопку, чтобы начать игру (кнопка все равно существует, потому что вы можете играть в несколько раундов), и представление уже раздуто и отображается, я получаю ширину и высоту сетки и вычисляю максимально возможный размер ячеек доски. Но этот подход, по-видимому, не является лучшей практикой.

Теперь я не знаю, что было бы правильно сделать. Я сделал что-то не так или есть какое-то решение, о котором я вообще не думал? Должен ли я экспериментировать с кучей эмулируемых устройств и создавать XML-файлы формы для разных размеров экрана? Подходит ли динамический подход?

Вот соответствующий код:

Файл XML-макета:

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