【问题标题】:Android programmatically added ConstraintLayout isn't shown on screenAndroid 以编程方式添加的 ConstraintLayout 未显示在屏幕上
【发布时间】:2020-02-09 19:30:41
【问题描述】:

我正在尝试创建一个系统的布局绘制,它与表格非常相似,因此,我尝试创建一个包含行和列的约束布局(我可能需要用线连接,因此,垂直/horizo​​ntal 布局不是最适合它)。

另外,由于系统大小不同,只有在运行时才知道,所以我必须以编程方式绘制布局。

我在构造这样的 ConstraintLayout 时遇到了问题 - 即使我已将所有元素添加到布局中,它也不会在屏幕上呈现它们。

我正在使用带有 Java 8 的 Android Pie(API 级别 28,为使用它的非常特定的设备创建它)。

我已按照以下文章中的说明进行操作:

  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. 创建一些模型数据
  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;
    }
}

【问题讨论】:

    标签: android android-constraintlayout android-9.0-pie programmatically


    【解决方案1】:

    在添加视图之前,您正在克隆 ConstraintSet。结果,视图 id 不出现在 ConstraintSet 中,无法连接。

    尝试将以下行移到 for 循环之后。

    conSet.clone(mScreenLayout);
    

    这可能无法解决所有问题,但可以帮助您入门。

    顺便说一句,如果您还不知道,“布局检查器”(工具->布局检查器)是从模拟器或设备查看布局的好方法。

    【讨论】:

      【解决方案2】:

      我在代码中发现了一些问题。

      首先是Cheticamp 指出的错误。我只需要调用 ConstraintSet.clone() 函数 我已经将 all 的按钮添加到布局中。

      但是,在我更改顺序后,我仍然将所有按钮排成一行,位于屏幕顶部。为了解决这个问题,我必须为所有按钮添加另一个约束 - 对于行 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;
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-01-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多