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!