3

OS X Yosemite 10.10.5 with Android Studio 2.0

For didactic purpose I want to move as many View attributes as I can from XML to Java.

I've got an android.support.v7.widget.RecyclerView inside a GridLayout and I want to move RecyclerView's android:layout_gravity.

From GridLayout.setGravity and R.attr documentation I know that layout_gravity is used by the child to set gravity attribute in the parent.

The following code is root cause of the exception:

GridLayout.LayoutParams parentParams = new GridLayout.LayoutParams();
parentParams.setGravity(Gravity.CENTER_VERTICAL);
container.setLayoutParams(parentParams);

The XML I want to shrink:

<GridLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/recycler_view_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/alphabet_recycler_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
    <!--android:layout_gravity="center_vertical">-->
    </android.support.v7.widget.RecyclerView>

</GridLayout>

This is the exception chain:

java.lang.ClassCastException: android.widget.GridLayout$LayoutParams cannot be cast to android.widget.FrameLayout$LayoutParams
at android.widget.FrameLayout.onMeasure(FrameLayout.java:431)
at android.support.v7.widget.ContentFrameLayout.onMeasure(ContentFrameLayout.java:135)
at android.view.View.measure(View.java:17430)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5463)
at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1436)
at android.widget.LinearLayout.measureVertical(LinearLayout.java:722)
at android.widget.LinearLayout.onMeasure(LinearLayout.java:613)
at android.view.View.measure(View.java:17430)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5463)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:430)
at android.view.View.measure(View.java:17430)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5463)
at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1436)
at android.widget.LinearLayout.measureVertical(LinearLayout.java:722)
at android.widget.LinearLayout.onMeasure(LinearLayout.java:613)
at android.view.View.measure(View.java:17430)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5463)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:430)
at com.android.internal.policy.impl.PhoneWindow$DecorView.onMeasure(PhoneWindow.java:2560)
at android.view.View.measure(View.java:17430)
at android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:2001)
at android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:1166)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1372)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1054)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:5779)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:767)
at android.view.Choreographer.doCallbacks(Choreographer.java:580)
at android.view.Choreographer.doFrame(Choreographer.java:550)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:753)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5221)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)

I looked up android.view.View.measure(View.java:17430) to find this:

if (cacheIndex < 0 || sIgnoreMeasureCache) {
    // measure ourselves, this should set the measured dimension flag back
    onMeasure(widthMeasureSpec, heightMeasureSpec);
    mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;
} else {

I don't really get how it ended up calling android.support.v7.widget.ContentFrameLayout.onMeasure instead of android.view.View.onMeasure

What am I missing?

3
  • show what is the container there please -- container.setLayoutParams(parentParams); Commented Apr 18, 2016 at 0:36
  • @dione llorera container is a GridLayout Commented Apr 18, 2016 at 11:34
  • @MPG which import statement are you talking about? Commented Apr 18, 2016 at 11:36

1 Answer 1

1

In the code snippet you provide:

GridLayout.LayoutParams parentParams = new GridLayout.LayoutParams();
parentParams.setGravity(Gravity.CENTER_VERTICAL);
container.setLayoutParams(parentParams);

it appears from the variable name container that you are attempting to apply the LayoutParams you construct to your GridLayout instance, rather than to your RecyclerView instance. I'd expect the final line to look something more like

recyclerView.setLayoutParams(parentParams);

If my assumption is correct, the parent of your GridLayout will end up attempting to parse the LayoutParams you built. This parent is unlikely(!) to itself be a GridLayout (I'd guess from the stack trace that it's a FrameLayout), and is choking when it tries to deal with GridLayout-specific LayoutParams.

Sign up to request clarification or add additional context in comments.

5 Comments

I AM applying LayoutParams to GridLayout because the layout_gravity is to be applied to the parent of the child. However RecyclerView.LayoutParams does not contain any method related to gravity.
While the parent is expected to parse those layout parameters, you must still apply them to the child (which will pass that information to the parent when requested). Consider the XML you are attempting to reproduce in code; the layout_gravity attribute is set on the child, not on the parent! Try applying your LayoutParams to the RecyclerView (i.e. the child) in code as I suggested - it should work as you expect.
RecyclerView.LayoutParams doesn't contain any method related to gravity. Do you mean I got to cast parentParams from GridLayout.LayoutParams to RecyclerView.LayoutParams
Nope, you should still be using a GridLayout$LayoutParams instance even though you're applying them to the RecyclerView. The LayoutParams type you use should match the parent ViewGroup type rather than the type of the child to which you are applying them. It's a weird API, that's for sure :)
Not only weird but also not properly documented. Anyway your solution works fine.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.