Создайте сетку (n × n) в Android ConstraintLayout с переменным числом n

Я хочу создать квадратную сетку внутри ConstraintLayout. Моя первая мысль заключалась в том, чтобы создать горизонтальную цепочку, задать некоторое значение запаса и установить для всех атрибутов размера одного вида width = match_constraint, height = match_constraint и установить соотношение 1: 1. Это работает и выглядит так:

Создайте сетку (n × n) в Android ConstraintLayout с переменным числом n

И это легко, когда размер сетки 2 × 2 - есть 4 элемента, поэтому это легко. Но что мне делать, когда мне нужно было создать сетку 7 × 7? У нас 49 представлений, поэтому настройка всех этих представлений может быть сложной задачей. Я хочу сделать это в макете ограничений, потому что хочу иметь гибкий макет. :)

Вы рассматривали возможность использования RecyclerView с числом пролетов 7?

Benjamin 19.07.2018 21:16

хм собственно нет :) но кое-какая идея верна. Но я не уверен, что это лучший способ решить эту проблему.

miosz 19.07.2018 21:18

это зависит от ваших потребностей, но я сомневаюсь, что вы поместите 49 квадратных изображений на одном экране одновременно

Benjamin 19.07.2018 21:19

вот почему для создания sqare используется "match_constraint" с соотношением 1: 1. Сетка 7x7 также есть например в игре 2048

miosz 19.07.2018 21:21

Как сказал @Benjamin, 49 просмотров на экране - плохая идея. Это много измерений, макета и т. д. Если вы собираетесь отображать контент, например изображения в квадратах, подумайте о RecyclerView с GridLayoutManager. Если вам нужно создать игровую доску (например, шахматную доску), лучшим решением будет иметь одно настраиваемое представление, переопределить его onDraw () и нарисовать несколько квадратов самостоятельно. Оба решения будут намного быстрее, чем одновременное отображение 49 просмотров на экране.

Veselin Todorov 20.07.2018 16:39
3
5
2 375
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Лучшая идея - создать два линейных макета представления, один с горизонтальным выравниванием, а другой с вертикальным выравниванием. Группа с вертикальным выравниванием - это группа, которую вы вызываете в своем макете и передаете ей в качестве атрибута число (7). Эта группа добавит к себе горизонтальную группу 7 раз. Каждая горизонтальная компоновка, в свою очередь, снова будет иметь номер (7). И это добавит 7 квадратов. Уловка состоит в том, чтобы увидеть, что каждый квадрат будет иметь одинаковый вес. И каждый горизонтальный ряд будет иметь одинаковый вес. Таким образом, вы получите сетки нужного размера, если вы вставите Verical layout в квадратную ViewGroup.

Ответ принят как подходящий

Поскольку вы говорите, что у вас есть переменное количество квадратов, я предполагаю, что вы хотите создать сетку n * n в коде. Вот подход к созданию сетки. Это только один способ, возможно, есть и другие.

Сначала создайте макет с ConstraintLayout в качестве корневого представления. В этом макете определите виджет, который имеет ширину и высоту match_constraints и ограничен родительским элементом. Это даст вам квадратный виджет независимо от ориентации устройства. (Я использую здесь View, чтобы его было видно, но лучше использовать виджет Space, хотя это, вероятно, не имеет особого значения.)

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>

Вот код действия, которое создает сетку 7 * 7. Мы будем использовать экранный вид из макета в качестве «родительского» вида для размещения квадратов.

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

Просто замените mRows и mCols, и сетка настроится сама. Если ваша сетка всегда будет квадратной, вам не нужно будет устанавливать соотношение контейнера сетки в коде. Вы также можете разместить свою сетку в более сложном макете. Просто убедитесь, что контейнер-сетка имеет правильные размеры, и все готово.

Это хороший ответ. Я просто ищу что-то подобное. Большое спасибо! ;)

miosz 22.07.2018 11:54

Теперь я увидел, что это работа, но есть проблема с производительностью. У меня лагает приложение и в логах: Я / Хореограф: Пропущено 133 кадра! Приложение может слишком много работать со своим основным потоком. I / Хореограф: Пропущено 65 кадров! Приложение может слишком много работать со своим основным потоком. Когда я расскажу, все это правильно

miosz 24.07.2018 19:41

@miosz Это большая работа над основным потоком. Если вы создаете матрицу снова и снова, это может быть проблемой. Если вы делаете это время от времени, это не должно быть проблемой. Это на эмуляторе? Эмулятор будет более чувствительным, чем реальное устройство. Я так понимаю, что вы не получаете ошибку ANR, так что тоже ничего страшного, если такое случается время от времени. Если производительность действительно является проблемой (медленной и заметной для пользователей), а не просто жалобой на logcat, вы можете рассмотреть способы ее ускорения.

Cheticamp 24.07.2018 19:48

нет на обычном устройстве (Nexus 5), и я один раз создаю матрицу. Но да, это выполнение действительно проблема (медленная). Что вы имеете в виду под ускорением? Или вы думаете, что создание этого в другом потоке может быть хорошей идеей? (как действие после публикации)

miosz 24.07.2018 19:52

@miosz Постарайтесь понять, где вы проводите время. В Studio есть несколько инструментов для измерения производительности, которые могут вам помочь. У меня нет большого опыта работы с ними, поэтому я не могу здесь помочь. Вы можете попробовать переместить часть работы из основного потока, но вы должны использовать основной поток для манипуляций с пользовательским интерфейсом. Вы также можете подумать о создании строительных блоков из 2, 3 ... 7 ... строк в XML и использовать код для их добавления и связывания. Всего лишь несколько идей, но ключом будет измерение; в противном случае вы можете просто крутить колеса.

Cheticamp 24.07.2018 20:00

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

miosz 25.07.2018 00:09

Если я правильно понял, я думаю, что лучший способ - использовать виджет Flow.

androidx.constraintlayout.helper.widget.Flow

и поместите идентификаторы всех представлений, которые должны быть включены в сетку, в следующее поле:

app:constraint_referenced_ids

дополнительную информацию можно найти здесь:

https://bignerdranch.com/blog/constraintlayout-flow-simple-grid-building-without-nested-layouts/

Другие вопросы по теме