0

Okay, here is what I am doing... I have two custom layouts:

HandedLayout extends ViewGroup

and

HandedPathLayout extends HandedLayout

So in the root layout, I have a custom LayoutParameters to accept a layout property, called handed. Here is the Layout Parameters class in

    public static class LayoutParams extends ViewGroup.LayoutParams {
    public int handed;
    public LayoutParams(Context c, AttributeSet attrs) {
        super(c, attrs);
        TypedArray a =
                c.obtainStyledAttributes(attrs, R.styleable.HandedLayout_LayoutParams);
        handed = a.getInt(R.styleable.HandedLayout_LayoutParams_layout_handed,
                HandedLayout.RIGHT_HANDED);
        a.recycle();
    }
    public LayoutParams(int width, int height) {
        super(width, height);
    }
}

And as I understand it (shakily, it seems), I also need to override 3 classes in HandedLayout. Here they are:

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

    }

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

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

So in the inner custom layout (HandedPathLayout), I need lots of layout parameters, so I do the exact same thing! Here is the LayoutParameters class inside of HandedPathLayout:

public static class LayoutParams extends HandedLayout.LayoutParams {

    public int[] endSides;
    public int[] endPositions;
    public int[] anchorSides;
    public int[] anchorPositions;
    public int controlPointDistance;

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

    public LayoutParams(Context context, AttributeSet attrs) {
        super(context, attrs);

        endSides = new int[2];
        endPositions = new int[2];
        anchorSides = new int[2];
        anchorPositions = new int[2];

        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.HandedPathLayout_LayoutParams);;
        try {
            //this is the second place that the default handedness is set, watch out!
            //handed = a.getInteger(R.styleable.HandedLayout_LayoutParams_layout_handed, HandedLayout.RIGHT_HANDED);
            endSides[0] = a.getInteger(R.styleable.HandedPathLayout_LayoutParams_layout_from_side, HandedLayout.BOTTOM_SIDE);
            endSides[1] = a.getInteger(R.styleable.HandedPathLayout_LayoutParams_layout_to_side, HandedLayout.PINKIE_SIDE);
            endPositions[0] = a.getDimensionPixelSize(R.styleable.HandedPathLayout_LayoutParams_layout_from_position, 0);
            endPositions[1] = a.getDimensionPixelSize(R.styleable.HandedPathLayout_LayoutParams_layout_to_position, 0);
            anchorSides[0] = a.getInteger(R.styleable.HandedPathLayout_LayoutParams_layout_anchor_up_side, HandedLayout.TOP_SIDE);
            anchorSides[1] = a.getInteger(R.styleable.HandedPathLayout_LayoutParams_layout_anchor_down_side, HandedLayout.BOTTOM_SIDE);
            //todo: should these positions be set relative to handedness?  which direction is zero?
            anchorPositions[0] = a.getDimensionPixelSize(R.styleable.HandedPathLayout_LayoutParams_layout_anchor_up_position, 0);
            anchorPositions[1] = a.getDimensionPixelSize(R.styleable.HandedPathLayout_LayoutParams_layout_anchor_down_position, 0);
            controlPointDistance = a.getInteger(R.styleable.HandedPathLayout_LayoutParams_layout_control_point_position, HandedLayout.BOTTOM_SIDE);

        } finally {
            a.recycle();
        }

    }

}

And then again, in the HandedPathLayout class, the three functions to make sure we get the right kind of LayoutParams:

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

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

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

I've tried this with and without the fully qualified LayoutParams class names.

So, now that's all there and compiles okay, and then in onMeasure of the root ViewGroup, the HandedLayout, I loop through the children and attempt to get at their getLayoutParams() so I can figure out where to put them and how to measure them, and I get this ClassCastException!

05-29 18:16:35.061 9391-9391/com.codesolutions.onehandkeyboard E/AndroidRuntime: FATAL EXCEPTION: main Process: com.codesolutions.onehandkeyboard, PID: 9391 java.lang.ClassCastException: com.codesolutions.pathlayout.HandedLayout$LayoutParams cannot be cast to com.codesolutions.pathlayout.HandedPathLayout$LayoutParams at com.codesolutions.pathlayout.HandedLayout.onMeasure(HandedLayout.java:90)

That exception is being thrown from this cast, which seems like it should get the right kind, in the debugger I've confirmed that the child is indeed a HandedPathLayout, and all indications are that the LayoutParams are of the correct type!

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

I just don't get why the LayoutParams are not of the correct type!

And another thing about this I don't get is about the custom View (extends TextView) that I want to put into my HandedPathLayout. It needs a custom layout_rows XML attribute, so do I need to make it it's own LayoutParams? Those are only for ViewGroups, right? But then it's the view that needs that attribute applied, and not the ViewGroup.

UPDATE:

So when I run the debugger and stop just before my cast that fails, in the onMeasure of HandedLayout... I find that, indeed, the LayoutParams objects are NEITHER of the types I expect! The getLayoutParams of the parent (the HandedLayout) returns a FrameLayout.LayoutParams (which makes no sense to me at all) and the child (which is a HandedPathLayout) has a HandedLayout.LayoutParams! WHY?! What am I not understanding here?

Thank you!

Joshua
  • 15
  • 5
  • The parameter in question is "layout_row"... it needs to apply only to the custom View (the inner most), but when I need it's value is in the onMeasure of CustomInnerLayout to correctly place the View. The view never needs to know it's own row even, since it only draws it's interior and the ViewGroup places it. So where do I keep this variable and how do I get it if not in the layout parameters? – Joshua May 29 '16 at 23:13
  • What makes you think `child.getLayoutParams();` will return `HandedPathLayout.LayoutParams` type of object? Also, please put the full error message, it doesn't say `ClassCastException` in the error message you have posted. – NecipAllef May 30 '16 at 02:15
  • well, since the child is a HandedPathLayout and I had overrided the generateLayoutParams, I thought that did it. I need the LayoutParams of the HandedPathLayout child to be a HandedPathLayout.LayoutPArams because I need the parameters that are defined in it! The error code I posed DOES say ClassCastException in it and says which class it can't cast... it says that the child (which is a HandedPathLayout) is returning a HandedLayout.LayoutParameters. – Joshua May 30 '16 at 14:46
  • java.lang.ClassCastException: com.codesolutions.pathlayout.HandedLayout$LayoutParams cannot be cast to com.codesolutions.pathlayout.HandedPathLayout$LayoutParams at com.codesolutions.pathlayout.HandedLayout.onMeasure(HandedLayout.java:90) – Joshua May 30 '16 at 14:46
  • I can confirm that the child is the correct type because I check for it's type before I try to get the LayoutParams from it: ` if (child.getClass().equals(HandedPathLayout.class)) { HandedPathLayout.LayoutParams lp = (HandedPathLayout.LayoutParams)child.getLayoutParams();` – Joshua May 30 '16 at 15:03
  • If you go through all the way how `getLayoutParams()` works, what it returns and what other methods it depends on in `ViewGroup` class I'm pretty sure you will find your answer. Just keep debugging. – NecipAllef May 31 '16 at 01:04
  • Also, I wanted you to post error log not because I don't believe you, but because I needed to see the full error message. And I also need to see what `onMeasure()` looks like but you didn't post it yet. It is almost impossible to know why your code fails if I don't see the full code and error log. Anyway, looks like you are making a false assumption somewhere, I wasn't surprised that you get `FrameLayout.LayoutParams` to be honest. I've done similar mistakes lots of times. All I can say is just keep debugging, keep track of `mLayoutParams` in every line. – NecipAllef May 31 '16 at 01:08
  • Thank you for your comments. I have been continuing to debug, and also finally found this [link](http://stackoverflow.com/questions/8942415/why-does-linearlayout-instance-getlayoutparams-look-to-have-a-wrong-class which seems to explain that I am thinking about this COMPLETELY wrong, and that the LayoutParams I'm supposed to have SHOULD be the type from the parent ViewGroup, not the ViewGroup I'm actually in. Right? I'm a little confused still about how that plays out in my program, but I'm going to try it that way and see. – Joshua May 31 '16 at 05:19
  • The `ViewGroup` your view is in IS your view's parent though. But you seem to be on the right path. Good luck! – NecipAllef May 31 '16 at 07:28

0 Answers0