Android программно добавленный ConstraintLayout не отображается на экране - PullRequest
1 голос
/ 09 февраля 2020

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

Кроме того, поскольку система имеет разные размеры, известные только при время выполнения , я должен нарисовать макет программно.

У меня проблема с созданием такого ConstraintLayout - даже если я добавил все элементы в макет, он не отображает их на экране.

Я использую Android P ie (API уровень 28, создавая его для очень специфических c устройств, использующих его), с Java 8.

Я следовал инструкциям, приведенным в следующих статьях:

  1. https://spin.atomicobject.com/2019/04/08/constraintlayout-chaining-views-programmatically/
  2. https://www.zoftino.com/adding-views-&-constraints-to-android-constraint-layout-programmatically

Прикрепление упрощенной версии моего кода (которая все еще не работает).

Код выполняет следующие действия:

  1. Создание некоторого макета данных a
  2. Для каждой строки:

    2.1. Создает и добавляет кнопки в соответствии с номерами в строке к макету general

    2.2. Подключите кнопки, используя general ConstrainSet

    2.3. Создайте цепочку из кнопок в текущей строке (так как я хочу, чтобы они были в той же высоте)

    2.4. Подсоедините нижний номер 0 к предыдущему ряду (или к верхней части экрана, это «центры» каждого ряда)

И код:

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

Ответы [ 2 ]

0 голосов
/ 10 февраля 2020

Есть несколько проблем, которые я обнаружил в коде.

Первый - это ошибка Cheticamp , на которую указывает. Мне нужно вызывать функцию ConstraintSet.clone () только после Я уже добавил все кнопок в макет.

Однако после того, как я изменил порядок, я все еще получил все кнопки в одной строке в верхней части экрана. Чтобы это исправить, мне пришлось добавить еще одно ограничение ко всем кнопкам - для каждой кнопки в строке R подключите bottom к bottom центральной кнопки в этом ряду, так что все выровняются в одном ряду.

Это решило мои основные проблемы в этом коде!

Вот мой полностью рабочий код (для справки других при необходимости):

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 int[][]             mButtonIds;
    private ConstraintLayout    mScreenLayout;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mScreenLayout = findViewById(R.id.main_layout);

        mButtonIds = new int[NUM_OF_ROWS][];

        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]

            Total: 15 stations
         */
        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();


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

        conSet.clone(mScreenLayout);

        for (int row = 0; row < NUM_OF_ROWS; ++row) {
            if (mButtonIds[row].length > 1) {
                connectAndChainRow(mButtonIds[row], centerIds[row], conSet);
            } else {
                conSet.centerHorizontally(centerIds[row], ConstraintSet.PARENT_ID);
            }
        }

        connectRows(conSet, centerIds);

        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,
                              int[] centerIds) {
        if (numsInRow.size() > 1) {
            addMultipleNumsRow(row, numsInRow, centerIds);
        }
        else if (numsInRow.size() == 1){
            addSingleNumRow(row, numsInRow.get(0), centerIds);
        }
    }

    private void connectRows(ConstraintSet conSet, int[] centerIds) {
        conSet.connect(ConstraintSet.PARENT_ID,
                       ConstraintSet.BOTTOM,
                       centerIds[0],
                       ConstraintSet.BOTTOM);

        for (int row = 0; row < NUM_OF_ROWS - 1; ++row) {
                conSet.connect(centerIds[row],
                               ConstraintSet.TOP,
                               centerIds[row + 1],
                               ConstraintSet.BOTTOM);
            }

        conSet.connect(centerIds[NUM_OF_ROWS - 1],
                       ConstraintSet.TOP,
                       ConstraintSet.PARENT_ID,
                       ConstraintSet.TOP);
    }

    private void connectAndChainRow(int[] rowButtonIds,
                                    int centerId,
                                    ConstraintSet conSet) {
        // First button will be attached to the left side of the parent
        conSet.connect(ConstraintSet.PARENT_ID,
                       ConstraintSet.LEFT,
                       rowButtonIds[0],
                       ConstraintSet.LEFT);

        for (int col = 0; col < rowButtonIds.length - 1; ++col) {
            conSet.connect(rowButtonIds[col],
                           ConstraintSet.RIGHT,
                           rowButtonIds[col + 1],
                           ConstraintSet.LEFT);

            if (rowButtonIds[col] != centerId) {
                conSet.connect(rowButtonIds[col],
                               ConstraintSet.BOTTOM,
                               centerId,
                               ConstraintSet.BOTTOM);
            }
        }

        if (rowButtonIds[rowButtonIds.length - 1] != centerId) {
            conSet.connect(rowButtonIds[rowButtonIds.length - 1],
                           ConstraintSet.BOTTOM,
                           centerId,
                           ConstraintSet.BOTTOM);
        }

        // Connecting to the right side of the parent
        conSet.connect(rowButtonIds[rowButtonIds.length - 1],
                       ConstraintSet.RIGHT,
                       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,
                                    int[] centerIds) {
        mButtonIds[row] = 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();
            mButtonIds[row][pos] = currButtonId;
            mScreenLayout.addView(button);

            if (pos == 0) {
                centerIds[row] = currButtonId;
            }
        }

        Log.i(logTag, "Created constrain chain and buttons for row: "
                      + row + " number of columns: "
                      + numsInRow.size());
    }

    private void addSingleNumRow(int row,
                                 int num,
                                 int[] centerIds) {
        Button button = createButton(row, num);
        button.setLayoutParams(new ConstraintLayout.LayoutParams(ConstraintLayout.LayoutParams.WRAP_CONTENT,
                                                                 ConstraintLayout.LayoutParams.WRAP_CONTENT));

        mScreenLayout.addView(button);

        mButtonIds[row] = new int[1];
        mButtonIds[row][0] = button.getId();

        centerIds[row] = button.getId();
    }

    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;
    }
}
0 голосов
/ 10 февраля 2020

Вы клонируете ConstraintSet перед добавлением своих представлений. В результате идентификаторы вида не появляются в ConstraintSet и не могут быть подключены.

Попробуйте переместить следующую строку после после для l oop.

conSet.clone(mScreenLayout);

Это, вероятно, не решит всех проблем, но поможет вам начать.

Кстати, если вы еще не знаете об этом, «Инспектор макетов» (Инструменты- > Layout Inspector) - хороший способ взглянуть на макет с помощью эмулятора или устройства.

...