Как определить пользовательские атрибуты для класса LayoutParams пользовательской реализации RecyclerView.LayoutManager?

Я знаю, как создавать пользовательские атрибуты для определенных классов. Вы просто определяете их в Styleable, используя имя класса для имени, например.

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

Затем, когда я использую экземпляры MyCustomView в своих макетах, customAttr1 и customAttr2 доступны для установки. Достаточно легко.

Что я пытаюсь сделать сейчас, так это использовать пользовательские атрибуты для LayoutParams в дочерних элементах моего пользовательского RecyclerView или, точнее, в корневом представлении файлов макета, которые питают отдельные подклассы RecyclerView.ViewHolder, которые я использую. Однако я не могу получить атрибуты, переданные мне, и я не уверен, почему бы и нет.

Вот мой файл attrs.xml...

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

Вот код в моем пользовательском классе LayoutParams, который считывает атрибуты...

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

И вот где я устанавливаю его в макете для одного из моих ViewHolder...

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

Тем не менее, ничто из того, что я пытаюсь, никогда не входит в вызов hasValue. Он всегда возвращается, как будто он не установлен.

Примечание. Я также пробовал все это при определении атрибутов...

<declare-styleable name="LayoutParams">

<declare-styleable name="ScrollableGridLayoutManager_LayoutParams">

<declare-styleable name="ScrollableGridAdapter_LayoutParams">

... но никто не работает.

Так что я делаю неправильно? Как вы определяете атрибуты, характерные для вашего пользовательского класса LayoutParams?


person Mark A. Donohoe    schedule 13.10.2017    source источник
comment
Примерно так же. Подклассы LayoutParams должны иметь конструктор, который принимает Context и AttributeSet, чтобы вы могли получать эти значения так же, как в подклассе View. Обязательно переопределите generateLayoutParams(AttributeSet) в пользовательском RecyclerView, чтобы вернуть подкласс LayoutParams. Кроме того, хотя вы можете использовать все, что вам нравится, я считаю, что соглашение состоит в том, чтобы добавить _Layout к пользовательскому name ViewGroup для LayoutParams' <declare-styleable>; например, name="MyCustomView_Layout".   -  person Mike M.    schedule 14.10.2017
comment
Я только что добавил свой код, который делает именно это. Проблема в том, что я не уверен, как определить атрибуты, потому что независимо от того, что я делаю в своих файлах макета, установленные мной атрибуты не отражаются в атрибутах, переданных в пользовательский конструктор LayoutParams. Они всегда сообщают, что не установлены. Это проблема, которую я пытаюсь преодолеть. (У меня такое чувство, что я разместил этот код, пока вы отвечали, поэтому вы, возможно, его не видели.)   -  person Mark A. Donohoe    schedule 14.10.2017
comment
Хм, ну, я только что собрал быстрый и грязный тест с RecyclerView, чтобы убедиться, что я ничего не упускаю из виду, и он работает, как и ожидалось. Как именно вы раздуваете макет элемента? Вы передаете родительский пользовательский RecyclerView в вызове inflate()?   -  person Mike M.    schedule 14.10.2017
comment
О, подождите, я вижу это сейчас. Вы используете неправильную перегрузку obtainStyledAttributes(). То есть вы забыли передать ему AttributeSet. Должно быть context.obtainStyledAttributes(attrs, R.styleable.ScrollableGridLayoutManager_LayoutParams);.   -  person Mike M.    schedule 14.10.2017
comment
Да !!! [лицо-ладонь] Я чувствую себя идиотом! Как я этого не видел? Однако вопрос... какое должно быть правильное значение для атрибута имени в теге declare-styleable... или это имеет значение (т.е. нет неправильного ответа, и это просто соглашение?)   -  person Mark A. Donohoe    schedule 14.10.2017
comment
Да, просто условность, насколько я знаю. Вы можете назвать его как угодно, потому что он будет использоваться только прямо в вашем XML и коде. После обработки и компиляции это все равно ints. Однако это с точки зрения только фреймворка и вашего кода. Могут быть некоторые инструменты анализа кода или что-то в этом роде, которые ожидают именно такой формат имени. Рад, что это сработало. Я опубликую ответ здесь через минуту. Ваше здоровье!   -  person Mike M.    schedule 14.10.2017


Ответы (1)


В пользовательском конструкторе LayoutParams вызов obtainStyledAttributes() должен включать переданный AttributeSet. В противном случае он извлекает значения только из темы Context, а значения атрибутов, указанные в макете XML, не будут включены в возвращенный TypedArray.

Например:

TypedArray styledAttrs =
    context.obtainStyledAttributes(attrs, R.styleable.ScrollableGridLayoutManager_LayoutParams);
person Mike M.    schedule 14.10.2017