1

Ironically enough I stumbled on a problem when I answered another question

The problem is that if I add a RelativeLayout as a child of my ICGridLayout the children of that RelativeLayout does not get the RelativeLayout.LayoutParams. This goes for all kinds of layouts that I add to my ICGridLayout. I've read through the source code for both LinearLayout, RelativeLayout, AbsoluteLayout and ViewGroup but have not found anything that gives me a hint of where I do something wrong. I also watched the Romain Guy's guide to created a FlowLayout in the hopes of getting an answer, alas that did not happen.

EDIT

Added my layout.xml file. It seems as if the children respond to above, below, toLeftOf, toRightOf and margins but not other relative layout rules.

As you can see I use simple XML layout.

Even if they children respond to the above rules, the eclipse (and android studio) auto complete does not recognise the xml attributes.

END EDIT

My attrs.xml file:

<?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>

And my ICGridLayout.java file:

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);
        }
    }

}

My layout.xml file:

<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>

I've spent at least 5 hours browsing SO and google in order to find an answer and that's why I'm writing my own question.

Thanks in advance. --Johan Risch

Community
  • 1
  • 1
Risch
  • 564
  • 7
  • 20
  • How are you creating the RelativeLayout and its children you put in ICGridLayout? It sounds like you're s imply not inflating/creating the children properly. Also note that @RemoteView won't do anything in your custom view, you should remove it. – Romain Guy Jun 14 '13 at 18:22
  • I've edited my question to show you my XML file. I hope it will shed some light on my issue. Thanks allot for your quick comment. – Risch Jun 14 '13 at 18:53
  • The XML looks fine (except that button1 has RelativeLayout parameters which will be ignored since the parent is a LinearLayout). How do you see that the children of RelativeLayout are not getting the right parameters type? – Romain Guy Jun 14 '13 at 23:04
  • Yeah, sorry. While putting up a simple example I forgot to remove the RelativeLayout params. In pure desperation I tried to compile it in Android Studio instead. And now it works. I will continue to investigare and if I find what was causing the problem I will post it here. – Risch Jun 15 '13 at 00:24

0 Answers0