1

具有讽刺意味的是,当我回答另一个问题时,我偶然发现了一个问题

问题是,如果我添加一个 RelativeLayout 作为我的 ICGridLayout 的子级,则该 RelativeLayout 的子级不会获得 RelativeLayout.LayoutParams。这适用于我添加到我的 ICGridLayout 的各种布局。我已经阅读了 LinearLayout、RelativeLayout、AbsoluteLayout 和 ViewGroup 的源代码,但没有找到任何提示我做错了什么的地方。我还观看了 Romain Guy 的创建FlowLayout的指南,希望得到答案,可惜这并没有发生。

编辑

添加了我的 layout.xml 文件。似乎孩子们响应了上、下、toLeftOf、toRightOf 和边距,而不是其他相关的布局规则。

如您所见,我使用简单的 XML 布局。

即使他们的孩子响应上述规则,eclipse(和android studio)自动完成也无法识别xml属性。

结束编辑

我的 attrs.xml 文件:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="ICGridLayout_Layout">
        <attr name="columns" format="integer"/>
        <attr name="layout_left" format="integer"/>
        <attr name="layout_top" format="integer"/>
        <attr name="layout_right" format="integer"/>
        <attr name="layout_bottom" format="integer"/>
        <attr name="layout_col_span" format="integer"/>
        <attr name="layout_row_span" format="integer"/>
        <attr name="layout_spacing" format="dimension"/>
    </declare-styleable>

</resources>

还有我的 ICGridLayout.java 文件:

package com.risch.evertsson.iclib.layout;

import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.RemoteViews.RemoteView;

import com.risch.evertsson.iclib.R;

/**
 * Created by johanrisch on 6/13/13.
 */
@RemoteView
public class ICGridLayout extends ViewGroup {
    private int mColumns = 4;
    private float mSpacing;

    public ICGridLayout(Context context) {
        super(context);
    }

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

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

    private void init(AttributeSet attrs) {
        TypedArray a = getContext().obtainStyledAttributes(
                attrs,
                R.styleable.ICGridLayout_Layout);
        this.mColumns = a.getInt(R.styleable.ICGridLayout_Layout_columns, 3);
        this.mSpacing = a.getDimension(R.styleable.ICGridLayout_Layout_layout_spacing, 0);
        a.recycle();
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        if (changed) {
            int width = (int) (r - l);
            int side = width / mColumns;
            int children = getChildCount();
            View child = null;
            for (int i = 0; i < children; i++) {
                child = getChildAt(i);
                LayoutParams lp = (LayoutParams) child.getLayoutParams();
                int left = (int) (lp.left * side + mSpacing / 2);
                int right = (int) (lp.right * side - mSpacing / 2);
                int top = (int) (lp.top * side + mSpacing / 2);
                int bottom = (int) (lp.bottom * side - mSpacing / 2);
                child.layout(left, top, right, bottom);
            }
        }
    }

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

    }

    private void measureVertical(int widthMeasureSpec, int heightMeasureSpec) {
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int width = 0;
        int height = 0;


        if (widthMode == MeasureSpec.AT_MOST || widthMode == MeasureSpec.EXACTLY) {
            width = MeasureSpec.getSize(widthMeasureSpec);
        } else {
            throw new RuntimeException("widthMeasureSpec must be AT_MOST or " +
                    "EXACTLY not UNSPECIFIED when orientation == VERTICAL");
        }


        View child = null;
        int row = 0;
        int side = width / mColumns;
        int childCount = getChildCount();
        for (int i = 0; i < childCount; i++) {
            child = getChildAt(i);

            LayoutParams lp = (LayoutParams) child.getLayoutParams();

            if (lp.bottom > row) {
                row = lp.bottom;
            }



            int childHeight = (lp.bottom - lp.top)*side;
            int childWidth = (lp.right-lp.left)*side;
            int heightSpec = getChildMeasureSpec(heightMeasureSpec, 0, childHeight);
            int widthSpec = getChildMeasureSpec(widthMeasureSpec, 0, childWidth);
            //            measureChild(child, widthMeasureSpec, heightMeasureSpec);
            child.measure(widthSpec, heightSpec);
        }
        height = row * side;
        // TODO: Figure out a good way to use the heightMeasureSpec...

        setMeasuredDimension(width, height);
    }

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

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

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

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

    public static class LayoutParams extends ViewGroup.MarginLayoutParams {
        int right = 1;
        int bottom = 1;
        int top = 0;
        int left = 0;
        int width = -1;
        int height = -1;

        public LayoutParams() {
            super(MATCH_PARENT, MATCH_PARENT);
            top = 0;
            left = 1;
        }

        public LayoutParams(int width, int height) {
            super(width, height);
            top = 0;
            left = 1;
        }

        public LayoutParams(Context context, AttributeSet attrs) {
            super(context, attrs);
            TypedArray a = context.obtainStyledAttributes(
                    attrs,
                    R.styleable.ICGridLayout_Layout);
            left = a.getInt(R.styleable.ICGridLayout_Layout_layout_left, 0);
            top = a.getInt(R.styleable.ICGridLayout_Layout_layout_top, 0);
            right = a.getInt(R.styleable.ICGridLayout_Layout_layout_right, left + 1);
            bottom = a.getInt(R.styleable.ICGridLayout_Layout_layout_bottom, top + 1);
            height = a.getInt(R.styleable.ICGridLayout_Layout_layout_row_span, -1);
            width = a.getInt(R.styleable.ICGridLayout_Layout_layout_col_span, -1);
            if (height != -1) {
                bottom = top + height;
            }
            if (width != -1) {
                right = left + width;
            }

            a.recycle();
        }

        public LayoutParams(ViewGroup.LayoutParams params) {
            super(params);
        }
        public LayoutParams(ViewGroup.MarginLayoutParams params) {
            super(params);
        }
    }

}

我的 layout.xml 文件:

<com.risch.evertsson.iclib.layout.ICGridLayout
    android:id="@+id/ICGridLayout1"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:spacing="4dp"
    app:columns="4" >

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_bottom="8"
        app:layout_left="0"
        app:layout_right="4"
        app:layout_top="0" >

        <Button
            android:id="@+id/button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentLeft="true"
            android:layout_alignParentTop="true"
            android:layout_marginLeft="90dp"
            android:layout_marginTop="109dp"
            android:text="Button" />

        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginBottom="16dp"
            android:background="#ffffff"
            android:layout_marginLeft="0dp"
            android:centerHorizontal="true"
            android:layout_below="@+id/button"
            android:orientation="vertical" >

             <Button
                 android:id="@+id/button1"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:layout_alignParentLeft="true"
                 android:layout_alignParentTop="true"
                 android:layout_marginLeft="90dp"
                 android:layout_marginTop="109dp"
                 android:text="Button" />

        </LinearLayout>

    </RelativeLayout>

</com.risch.evertsson.iclib.layout.ICGridLayout>

我花了至少 5 个小时浏览 SO 和 google 以找到答案,这就是我写自己的问题的原因。

提前致谢。——约翰·里施

4

0 回答 0