androidandroid-layoutandroid-recyclerviewcustom-attributesandroid-custom-attributes

How do you define custom attributes for the LayoutParams class of a custom RecyclerView.LayoutManager implementation?


I know how to create custom attributes for specific classes. You simply define them in a Styleable using the class name for the name, like so.

<declare-styleable name="MyCustomView">
    <attr name="customAttr1" format="integer" />
    <attr name="customAttr2" format="boolean" />
</declare-styleable>

Then, when I use instances of MyCustomView in my layouts, customAttr1 and customAttr2 are available to set. Easy enough.

What I'm trying to do now is use custom attributes for the LayoutParams on the children of my custom RecyclerView, or more accurately, in the root view of the layout files that feed the individual RecyclerView.ViewHolder subclasses I'm using. However, I can't get the attributes handed to me and I'm not sure why not.

Here's my attrs.xml file...

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <declare-styleable name="ScrollableGridLayoutManager.LayoutParams">
        <attr name="cellLayoutMode">
            <enum name="scrollable"                 value="0" />
            <enum name="fixedHorizontal"            value="1" />
            <enum name="fixedVertical"              value="2" />
            <enum name="fixedHorizontalAndVertical" value="3" />
        </attr>
    </declare-styleable>

</resources>

Here's the code in my custom LayoutParams class that reads the attributes...

public LayoutParams(Context context, AttributeSet attrs){

    super(context, attrs);

    TypedArray styledAttrs = context.obtainStyledAttributes(R.styleable.ScrollableGridLayoutManager_LayoutParams);

    if(styledAttrs.hasValue(R.styleable.ScrollableGridLayoutManager_LayoutParams_cellLayoutMode)){
        int layoutModeOrdinal = styledAttrs.getInt(R.styleable.ScrollableGridLayoutManager_LayoutParams_cellLayoutMode, layoutMode.ordinal());
        layoutMode = LayoutMode.values()[layoutModeOrdinal];
    }

    styledAttrs.recycle();
}

And here's where I'm setting it in the layout for one of my ViewHolders...

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android = "http://schemas.android.com/apk/res/android"
    xmlns:app     = "http://schemas.android.com/apk/res-auto"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:gravity="start|center_vertical"
    android:background="#0000FF"
    app:cellLayoutMode="fixedVertical">

    <TextView
        android:id="@+id/mainTextView"
        android:textColor="#000000"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="#FFFF00"
        android:layout_marginStart="20dp" />

</LinearLayout>

However, nothing I try seems to ever go inside the 'hasValue' call. It always returns like it isn't set.

Note: I've also tried all of these when defining the attributes...

<declare-styleable name="LayoutParams">

<declare-styleable name="ScrollableGridLayoutManager_LayoutParams">

<declare-styleable name="ScrollableGridAdapter_LayoutParams">

...but none seem to work.

So what am I doing wrong? How do you define attributes specific to your custom LayoutParams class?


Solution

  • In the custom LayoutParams constructor, the obtainStyledAttributes() call must include the AttributeSet passed in. Otherwise, it's pulling values from just the Context's theme, and those attribute values specified in the layout XML won't be included in the returned TypedArray.

    For example:

    TypedArray styledAttrs =
        context.obtainStyledAttributes(attrs, R.styleable.ScrollableGridLayoutManager_LayoutParams);