You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

onCreate中动态添加TextView到ConstraintLayout无效,点击触发正常

问题根源与解决方案

核心原因

在onCreate方法执行时,Android的视图布局测量流程还未完成,你的ConstraintLayout(R.id.grid)还没有实际绘制到屏幕上,此时调用grid.getHeight()会返回0。按你的计算逻辑:

int cellSize = (grid.getHeight() - (gapSize * (gridSize  + 1))) / gridSize;

得到的cellSize会是负数或0,给TextView设置这种无效的宽高参数后,自然无法在界面上显示。而通过点击事件触发时,界面已经完成布局,grid.getHeight()能拿到真实尺寸,所以网格正常显示。

解决方案

方法1:用View.post()延迟执行网格生成

利用post()方法将generateGrid的调用放到UI线程的消息队列末尾,等视图完成布局测量后再执行:

修改你的onCreate方法:

@Override
protected void onCreate(Bundle savedInstanceState) {
    setTheme(Utils.currentTheme);
    super.onCreate(savedInstanceState);
    setContentView(R.layout.duek48);

    ConstraintLayout grid = findViewById(R.id.grid);
    // 延迟到视图布局完成后执行
    grid.post(this::generateGrid);
}

同时简化generateGrid方法(去掉无用的View v参数,把findViewById移到循环外提升性能):

public void generateGrid() {
    ConstraintLayout grid = findViewById(R.id.grid);
    TextView previousCell = null;
    int gapSize = 16;
    // 获取真实的网格高度后计算单元格尺寸,加容错避免负数
    int cellSize = Math.max((grid.getHeight() - (gapSize * (gridSize + 1))) / gridSize, 1);

    for (int i = 0; i < gridSize * gridSize; i++) {
        TextView gridBackgroundCell = new TextView(this);
        gridBackgroundCell.setId(View.generateViewId());
        gridBackgroundCell.setText("");
        // 先设置Drawable再设置Tint,确保着色生效
        gridBackgroundCell.setBackground(getResources().getDrawable(R.drawable.rounded_view));
        gridBackgroundCell.setBackgroundTintList(ColorStateList.valueOf(Color.rgb(170, 170, 170)));
        
        ConstraintLayout.LayoutParams layoutParams = new ConstraintLayout.LayoutParams(cellSize, cellSize);
        if (previousCell == null) {
            layoutParams.topMargin = gapSize;
            layoutParams.topToTop = R.id.grid;
            layoutParams.startToStart = R.id.grid;
        } else {
            if (i % gridSize == 0) {
                layoutParams.topMargin = gapSize;
                layoutParams.topToBottom = previousCell.getId();
                layoutParams.startToStart = R.id.grid;
            } else {
                layoutParams.topMargin = 0;
                layoutParams.topToTop = previousCell.getId();
                layoutParams.startToEnd = previousCell.getId();
            }
        }
        layoutParams.leftMargin = gapSize;
        gridBackgroundCell.setLayoutParams(layoutParams);
        grid.addView(gridBackgroundCell);

        previousCell = gridBackgroundCell;
    }
}

方法2:监听视图布局完成事件

通过ViewTreeObserver监听布局完成回调,确保拿到真实尺寸后再执行生成逻辑:

@Override
protected void onCreate(Bundle savedInstanceState) {
    setTheme(Utils.currentTheme);
    super.onCreate(savedInstanceState);
    setContentView(R.layout.duek48);

    ConstraintLayout grid = findViewById(R.id.grid);
    grid.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            // 移除监听,避免重复触发
            grid.getViewTreeObserver().removeOnGlobalLayoutListener(this);
            generateGrid();
        }
    });
}

额外优化建议

  • 自适应GapSize:可以根据gridSize动态调整间隙大小,比如用网格宽度的百分比计算,避免固定值导致不同网格尺寸下布局失衡。
  • 避免重复findViewById:原代码中每次循环都调用findViewById(R.id.grid),这会浪费性能,建议像上面的代码一样,把它放到循环外。

内容的提问来源于stack exchange,提问作者FishFeetSlapper

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 01:10:57