【问题标题】:Child views in a custom viewgroup not following boundaries自定义视图组中的子视图不遵循边界
【发布时间】:2013-04-03 02:24:47
【问题描述】:

我正在创建一个自定义布局(视图组子类),它将自身划分为单元格,然后根据单元格位置和单元格宽度/高度定位子布局。

把它想象成小部件的组织方式。

我添加了一堆具有不同背景颜色的框架布局,它们似乎定位正确。但是,当我放入 textview 时,它会在垂直方向上扩展得远远超出该范围,并在水平方向上保持固定宽度。不过这个位置工作正常。

代码:

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;

public class DynamicLayout extends ViewGroup {

int numCellsX = 6, numCellsY = 8;
int cellSize;

int blockMap[];

public DynamicLayout(Context context) {
    super(context);

    init();
}

public DynamicLayout(Context context, AttributeSet attrs) {
    super(context, attrs);
    init();
}

public DynamicLayout(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    init();
}

private void init()
{
    blockMap = new int[numCellsX * numCellsY];
    clearBlockMap();
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);

    cellSize = getMeasuredWidth() / numCellsX;

    int specWidth = MeasureSpec.getSize(widthMeasureSpec);
    int specHeight = MeasureSpec.getSize(heightMeasureSpec);

    this.setMeasuredDimension(specWidth, specHeight);

    super.onMeasure(widthMeasureSpec, heightMeasureSpec);

    if (getChildCount() > 0) {
        int wspec = MeasureSpec.makeMeasureSpec(getMeasuredWidth()
                / getChildCount(), MeasureSpec.EXACTLY);
        int hspec = MeasureSpec.makeMeasureSpec(getMeasuredHeight(),
                MeasureSpec.EXACTLY);
        for (int i = 0; i < getChildCount(); i++) {
            View v = getChildAt(i);
            v.measure(wspec, hspec);
        }
    }
    Log.i("DYNA", "Measured");
}

@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
    Log.i("DYNA", "On Layout");

    clearBlockMap();

    for (int i = 0; i < getChildCount(); i++) {
        View v = getChildAt(i);

        if (v instanceof DynaServiceView) {
            DynaServiceView serviceView = (DynaServiceView) v;

            if (serviceView.getVisibility() == GONE) 
                continue;


            int x = serviceView.getXPos();
            int y = serviceView.getYPos();
            int width = serviceView.getXCells();
            int height = serviceView.getYCells();

            //Is the thing too big?
            if (width > numCellsX)
            {
                Log.i("DYNA", "Warning, service too big, shrinking to size");
                width = numCellsX;
                serviceView.setWidth(width);
            }

            //Is there space?
            if (checkBlockMap(x, y, width, height))
            {
                Log.i("DYNA", "Found collision at child " + i +", resolving...");
                //Find somewhere to put this
                boolean foundSpot = false;
                for (int j = y; j <= numCellsY - height; j++)
                {
                    for (int k = x; k <= numCellsX - width; k++)
                    {
                        if (!checkBlockMap(k, j, width, height))
                        {
                            x = k;
                            y = j;                              
                            foundSpot = true;
                            break;
                        }
                    }

                    if (foundSpot)
                        break;
                }

                if (!foundSpot)                 
                    Log.i("DYNA", "No spot for child at: " + i + ", skipping!");
                else
                    Log.i("DYNA", "Resolved! New X/Y: " + x + ", " + y);
            }

            setBlockMap(x, y, width, height);

            //Has spot now, set layout
            serviceView.layout(l + (x * cellSize), t + (y * cellSize), (x * cellSize)
                    + (width * cellSize), (y * cellSize)
                    + (height * cellSize));
        }

    }       
}

private boolean checkBlockMap(int x, int y, int width, int height)
{
    for (int  j= y; j < y + height; j++)
    {
        for (int k = x; k < x + width; k++)                     
            if (blockMap[(j * numCellsX) + k] == 1)
                return true;
    }
    return false;
}

private void setBlockMap(int x, int y, int width, int height)
{
    for (int  j= y; j < y + height; j++)
    {
        for (int k = x; k < x + width; k++)                     
            blockMap[(j * numCellsX) + k] = 1;
    }
}

private void clearBlockMap()
{
    for (int i = 0; i < blockMap.length;i++)
        blockMap[i] = 0;
}
}

这是一张解释问题的图片。在右侧,您可以看到布局的边框正确排列,但在左侧,子文本视图显然没有跟随它。

【问题讨论】:

    标签: java android android-layout


    【解决方案1】:

    发现问题.... onMeasure 设置不正确。愚蠢的错误。

    【讨论】:

    • 我正在考虑做一些与此非常相似的事情。出于好奇,使用它时 XML 布局是什么样的,或者您是否以编程方式使用此 ViewGroup?
    • 他们的布局都在程序中,但你可以使用像线性或相对布局这样的布局,图片是从中获取的。 Android GUI 编辑器足够先进,可以及时运行代码并显示其外观。
    • 感谢您的信息。我决定将在运行时为项目计算的边距用于RelativeLayout 中的视图。它可能效率较低,但在我找到换出布局的理由之前,我可能会暂时使用它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-19
    • 1970-01-01
    • 1970-01-01
    • 2020-11-16
    相关资源
    最近更新 更多