自定义android ViewGroup儿童的孩子没有布局

时间:2023-01-12 17:59:51

I've made a very simple ViewGroup subclass, "QuadLayout", which is intended to divide the view's space into equal quarters, and lay the children out appropriately.

我创建了一个非常简单的ViewGroup子类“QuadLayout”,它旨在将视图的空间划分为相等的四分之一,并将孩子们放在适当的位置。

Note, this layout is "dumb" - it doesn't attempt to calculate children's preferred heights or widths, no gravity, etc. It just sets four children into top-left, top-right, bottom-left, & bottom-right quadrants. The only reason I wrote this layout is because TableLayout & GridLayout refuse to give me even row heights. They seem to defer to children height preferences, and instead of an even row height, I get one short row and one tall row.

请注意,这种布局是“哑” - 它不会尝试计算儿童的首选高度或宽度,没有重力等。它只是将四个孩子设置为左上,右上,左下和右下象限。我写这个布局的唯一原因是因为TableLayout和GridLayout拒绝给我甚至行高。他们似乎更喜欢孩子的身高偏好,而不是偶数行高,我得到一个短行和一个高行。

Now, the children I'm laying out are CardView subclasses, and they inflate a layout with a few TextViews and an ImageView. Very simple layout for each card.

现在,我正在布局的孩子是CardView子类,他们用几个TextView和一个ImageView来扩展布局。每张卡的布局非常简单。

Here's the problem.

这是问题所在。

When I use TableLayout or GridLayout (with the aforementioned row sizing issues) the card's contents are rendered.

当我使用TableLayout或GridLayout(具有上述行大小调整问题)时,将呈现卡的内容。

When I use my QuadLayout, the cards are correctly laid out, but the card's TextViews, and ImageViews are not visible. I've stepped through with the debugger and confirmed the card's layout is being inflated, and the TextViews and ImageViews are being found and are not-null. And the appropriate model data is being assigned.

当我使用QuadLayout时,卡片的布局正确,但卡片的TextViews和ImageViews不可见。我已经使用调试器并确认卡的布局正在膨胀,并且TextViews和ImageViews正在被找到并且不为null。并且正在分配适当的模型数据。

I've overridden onLayout in my CardView subclass, and I've confirmed that while the CardView itself is assigned correct layout (left,top,right,bottom) its children do not get laid out! They all have left/right/top/bottom of 0!

我已经在我的CardView子类中覆盖了onLayout,并且我已经确认,虽然CardView本身被分配了正确的布局(左,上,右,下),但它的孩子却没有布局!他们都有0的左/右/上/下!

public class QuadLayout extends ViewGroup {

    private static final String TAG = "QuadLayout";

    private Rect childRect = new Rect();

    public QuadLayout(Context context) {
        super(context);
        setWillNotDraw(true);
    }

    public QuadLayout(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
        setWillNotDraw(true);
    }

    public QuadLayout(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        setWillNotDraw(true);
    }

    @Override
    public boolean shouldDelayChildPressedState() {
        // we don't scroll children
        return false;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        measureChildren(widthMeasureSpec,heightMeasureSpec);
        int width = MeasureSpec.getSize(widthMeasureSpec);
        int height = MeasureSpec.getSize(heightMeasureSpec);
        setMeasuredDimension(width, height);
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        int innerLeft = this.getPaddingLeft();
        int innerTop = this.getPaddingTop();
        int innerRight = this.getMeasuredWidth() - this.getPaddingRight();
        int innerBottom = this.getMeasuredHeight() - this.getPaddingBottom();
        int innerWidth = innerRight - innerLeft;
        int innerHeight = innerBottom - innerTop;
        int horizontalCenter = innerLeft + (int) (Math.ceil(innerWidth / 2f));
        int verticalCenter = innerTop + (int) (Math.ceil(innerHeight / 2f));
        int count = getChildCount();

        for (int i = 0; i < count; i++) {
            View child = getChildAt(i);

            if (child.getVisibility() != View.GONE) {
                switch (i) {
                    case 0: {
                        childRect.left = innerLeft;
                        childRect.top = innerTop;
                        childRect.right = horizontalCenter;
                        childRect.bottom = verticalCenter;
                        break;
                    }
                    case 1: {
                        childRect.left = horizontalCenter;
                        childRect.top = innerTop;
                        childRect.right = innerRight;
                        childRect.bottom = verticalCenter;
                        break;
                    }
                    case 2: {
                        childRect.left = innerLeft;
                        childRect.top = verticalCenter;
                        childRect.right = horizontalCenter;
                        childRect.bottom = innerBottom;
                        break;
                    }
                    case 3: {
                        childRect.left = horizontalCenter;
                        childRect.top = verticalCenter;
                        childRect.right = innerRight;
                        childRect.bottom = innerBottom;
                        break;
                    }

                    default:
                        throw new IllegalStateException("QuadLayout only supports a max of 4 children");
                }

                LayoutParams lp = (LayoutParams) child.getLayoutParams();
                childRect.left += lp.leftMargin;
                childRect.top += lp.topMargin;
                childRect.right -= lp.rightMargin;
                childRect.bottom -= lp.bottomMargin;

                child.layout(childRect.left, childRect.top, childRect.right, childRect.bottom);
            }
        }
    }

    @Override
    public LayoutParams generateLayoutParams(AttributeSet attrs) {
        return new LayoutParams(getContext(), attrs);
    }

    @Override
    protected LayoutParams generateDefaultLayoutParams() {
        return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
    }

    @Override
    protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
        return new LayoutParams(p);
    }

    @Override
    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
        return p instanceof LayoutParams;
    }

    public static class LayoutParams extends MarginLayoutParams {

        public LayoutParams(Context c, AttributeSet attrs) {
            super(c, attrs);
        }

        public LayoutParams(int width, int height) {
            super(width, height);
        }

        public LayoutParams(ViewGroup.LayoutParams source) {
            super(source);
        }

    }

}

Thanks in advance,

提前致谢,

2 个解决方案

#1


I was having the same problem and just solved it by comparing my code to FrameLayout's code.

我遇到了同样的问题,只是通过将我的代码与FrameLayout的代码进行比较来解决它。

You should call child.measure() on each of your layout's children. It almost doesn't matter what spec you give to them.

您应该在每个布局的子项上调用child.measure()。你给他们的规格几乎无关紧要。

#2


Since nobody had better answer I will share my hack to divide the screen to four parts. You could implement this bevaviour into your QuadLayout - I'll explain the basic idea in XML

由于没有人有更好的答案,我将分享我的黑客将屏幕划分为四个部分。你可以在你的QuadLayout中实现这个bevaviour - 我将用XML解释基本思想

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <View
        android:id="@+id/center"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_centerInParent="true" />

    <android.support.v7.widget.CardView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_alignParentLeft="true"
        android:layout_toLeftOf="@+id/center"
        android:layout_alignBottom="@+id/center"/>

    <android.support.v7.widget.CardView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_alignParentRight="true"
        android:layout_toRightOf="@+id/center"
        android:layout_alignBottom="@+id/center"/>

    <android.support.v7.widget.CardView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentLeft="true"
        android:layout_toLeftOf="@+id/center"
        android:layout_alignTop="@+id/center"/>

    <android.support.v7.widget.CardView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"
        android:layout_toRightOf="@+id/center"
        android:layout_alignTop="@+id/center"/>

</RelativeLayout>

This should render properly, hope it helps you!

这应该正确呈现,希望它可以帮助你!

#1


I was having the same problem and just solved it by comparing my code to FrameLayout's code.

我遇到了同样的问题,只是通过将我的代码与FrameLayout的代码进行比较来解决它。

You should call child.measure() on each of your layout's children. It almost doesn't matter what spec you give to them.

您应该在每个布局的子项上调用child.measure()。你给他们的规格几乎无关紧要。

#2


Since nobody had better answer I will share my hack to divide the screen to four parts. You could implement this bevaviour into your QuadLayout - I'll explain the basic idea in XML

由于没有人有更好的答案,我将分享我的黑客将屏幕划分为四个部分。你可以在你的QuadLayout中实现这个bevaviour - 我将用XML解释基本思想

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <View
        android:id="@+id/center"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_centerInParent="true" />

    <android.support.v7.widget.CardView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_alignParentLeft="true"
        android:layout_toLeftOf="@+id/center"
        android:layout_alignBottom="@+id/center"/>

    <android.support.v7.widget.CardView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_alignParentRight="true"
        android:layout_toRightOf="@+id/center"
        android:layout_alignBottom="@+id/center"/>

    <android.support.v7.widget.CardView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentLeft="true"
        android:layout_toLeftOf="@+id/center"
        android:layout_alignTop="@+id/center"/>

    <android.support.v7.widget.CardView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"
        android:layout_toRightOf="@+id/center"
        android:layout_alignTop="@+id/center"/>

</RelativeLayout>

This should render properly, hope it helps you!

这应该正确呈现,希望它可以帮助你!