Я потратил некоторое время, пытаясь найти способ добавить заголовок в файл RecyclerView
, но безуспешно.
Вот что у меня получилось:
@Override
protected void onCreate(Bundle savedInstanceState) {
...
layouManager = new LinearLayoutManager(getActivity());
recyclerView.setLayoutManager(layouManager);
LayoutInflater inflater = (LayoutInflater) getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
headerPlaceHolder = inflater.inflate(R.layout.view_header_holder_medium, null, false);
layouManager.addView(headerPlaceHolder, 0);
...
}
LayoutManager
, Кажется, обработка расположения объекта RecyclerView
элементов. Так как я не мог найти какой - либо addHeaderView(View view)
метод, я решил пойти с LayoutManager
«S addView(View view, int position)
метода и добавить мой взгляд заголовка в первом положении , чтобы действовать в качестве заголовка.
И вот здесь все становится еще уродливее:
java.lang.NullPointerException: Attempt to read from field 'android.support.v7.widget.RecyclerView$ViewHolder android.support.v7.widget.RecyclerView$LayoutParams.mViewHolder' on a null object reference
at android.support.v7.widget.RecyclerView.getChildViewHolderInt(RecyclerView.java:2497)
at android.support.v7.widget.RecyclerView$LayoutManager.addViewInt(RecyclerView.java:4807)
at android.support.v7.widget.RecyclerView$LayoutManager.addView(RecyclerView.java:4803)
at com.mathieumaree.showz.fragments.CategoryFragment.setRecyclerView(CategoryFragment.java:231)
at com.mathieumaree.showz.fragments.CategoryFragment.access$200(CategoryFragment.java:47)
at com.mathieumaree.showz.fragments.CategoryFragment$2.success(CategoryFragment.java:201)
at com.mathieumaree.showz.fragments.CategoryFragment$2.success(CategoryFragment.java:196)
at retrofit.CallbackRunnable$1.run(CallbackRunnable.java:41)
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)
После нескольких NullPointerExceptions
попыток вызвать addView(View view)
в разные моменты создания Activity (также попытался добавить представление, когда все настроено, даже данные адаптера), я понял, что понятия не имею, правильный ли это способ сделать это (и он не похоже).
PS: Кроме GridLayoutManager
того, LinearLayoutManager
было бы очень полезно решение, которое могло бы обрабатывать в дополнение к !
источник
Ответы:
Мне пришлось добавить нижний колонтитул к моему,
RecyclerView
и здесь я делюсь своим фрагментом кода, поскольку думал, что он может быть полезен. Пожалуйста, проверьте комментарии внутри кода, чтобы лучше понять общий поток.Приведенный выше фрагмент кода добавляет нижний колонтитул к файлу
RecyclerView
. Вы можете проверить этот репозиторий GitHub для проверки реализации добавления как верхнего, так и нижнего колонтитула.источник
RecyclerView
динамически заполнять свой . Вы можете контролировать каждый из элементов вашегоRecyclerView
. Пожалуйста, посмотрите раздел кода для рабочего проекта. Надеюсь, это поможет. github.com/comeondude/dynamic-recyclerview/wikiint getItemViewType (int position)
- Вернуть тип представления элемента в позиции для повторного использования представления. Реализация этого метода по умолчанию возвращает 0, делая предположение о единственном типе представления для адаптера. В отличие отListView
адаптеров, типы не обязательно должны быть смежными. Рассмотрите возможность использования ресурсов идентификатора для однозначной идентификации типов представления элементов. - Из документации. developer.android.com/reference/android/support/v7/widget/…Решить очень просто !!
Мне не нравится идея иметь логику внутри адаптера как другой тип представления, потому что он каждый раз проверяет тип представления перед возвратом представления. Решение, приведенное ниже, позволяет избежать дополнительных проверок.
Просто добавьте вид заголовка LinearLayout (вертикальный) + recyclerview + вид нижнего колонтитула внутри android.support.v4.widget.NestedScrollView .
Проверь это:
Добавьте эту строку кода для плавной прокрутки
Это приведет к потере всех характеристик RV, и RV попытается выложить всех держателей просмотров независимо
layout_height
от RV.Рекомендуется использовать для списка небольшого размера, такого как панель навигации, настройки и т. Д.
источник
RecyclerView
- вы теряете реальную переработку и оптимизацию, которую она приносит.У меня была такая же проблема с Lollipop, и я создал два подхода для обертывания
Recyclerview
адаптера. Один из них довольно прост в использовании, но я не уверен, как он будет вести себя с изменяющимся набором данных. Потому что он обертывает ваш адаптер, и вам нужно убедиться, что вы вызываете методы, какnotifyDataSetChanged
на правильном объекте адаптера.У другого таких проблем быть не должно. Просто позвольте вашему обычному адаптеру расширить класс, реализовать абстрактные методы, и вы должны быть готовы. И вот они:
логи
new HeaderRecyclerViewAdapterV1(new RegularAdapter());
RegularAdapter extends HeaderRecyclerViewAdapterV2
HeaderRecyclerViewAdapterV1
HeaderRecyclerViewAdapterV2
Отзывы и вилки приветствуются. Я буду использовать
HeaderRecyclerViewAdapterV2
самостоятельно и развивать, тестировать и публиковать изменения в будущем.РЕДАКТИРОВАТЬ : @OvidiuLatcu Да, у меня были проблемы. На самом деле я перестал неявно компенсировать заголовок
position - (useHeader() ? 1 : 0)
и вместо этого создал для него общедоступный методint offsetPosition(int position)
. Потому что, если вы установитеOnItemTouchListener
Recyclerview, вы можете перехватить касание, получить координаты x, y касания, найти соответствующее дочернее представление, а затем вызвать,recyclerView.getChildPosition(...)
и вы всегда получите несмещенное положение в адаптере! Это недостаток кода RecyclerView, я не вижу простого способа преодолеть это. Вот почему я теперь явно смещаю позиции, когда мне нужно, своим собственным кодом.источник
Я не пробовал этого, но я бы просто добавил 1 (или 2, если вы хотите и верхний, и нижний колонтитул) к целому числу, возвращаемому getItemCount в вашем адаптере. Затем вы можете переопределить
getItemViewType
в своем адаптере, чтобы он возвращал другое целое число, когдаi==0
: https://developer.android.com/reference/android/support/v7/widget/RecyclerView.Adapter.html#getItemViewType(int)createViewHolder
затем передается целое число, из которого вы вернулисьgetItemViewType
, что позволяет вам по-разному создавать или настраивать держатель представления для представления заголовка: https://developer.android.com/reference/android/support/v7/widget/RecyclerView.Adapter.html# createViewHolder (android.view.ViewGroup , интервал )Не забудьте вычесть единицу из переданного целого числа позиции
bindViewHolder
.источник
getItemViewType(int position) { return position == 0 ? 0 : 1; }
(RecyclerView
нетgetViewTypeCount()
метода). С другой стороны, я согласен с @IZI_Shadow_IZI, я действительно чувствую, что LayoutManager должен быть тем, кто занимается такими вещами. Есть еще идеи?Вы можете использовать эту библиотеку GitHub, позволяющую добавлять верхний и / или нижний колонтитулы в ваш RecyclerView самым простым способом.
Вам нужно добавить библиотеку HFRecyclerView в свой проект или вы также можете получить ее из Gradle:
Это результат на изображении:
РЕДАКТИРОВАТЬ:
Если вы просто хотите добавить поля вверху и / или внизу с помощью этой библиотеки: SimpleItemDecoration :
источник
В итоге я реализовал свой собственный адаптер, чтобы обернуть любой другой адаптер и предоставить методы для добавления представлений верхнего и нижнего колонтитула.
Создал суть здесь: HeaderViewRecyclerAdapter.java
Основная функция, которую я хотел, - это интерфейс, аналогичный ListView, поэтому я хотел иметь возможность расширять представления в моем фрагменте и добавлять их в файл
RecyclerView
inonCreateView
. Это делается путемHeaderViewRecyclerAdapter
передачи адаптера для обертывания и вызоваaddHeaderView
иaddFooterView
передачи ваших расширенных представлений. Затем установитеHeaderViewRecyclerAdapter
экземпляр как адаптер наRecyclerView
.Дополнительным требованием было то, что мне нужно было легко менять адаптеры, сохраняя при этом верхние и нижние колонтитулы, я не хотел иметь несколько адаптеров с несколькими экземплярами этих верхних и нижних колонтитулов. Таким образом, вы можете позвонить,
setAdapter
чтобы изменить обернутый адаптер, оставив без изменений верхние и нижние колонтитулы, сRecyclerView
уведомлением об изменении.источник
мой способ "держать это просто глупо" ... он тратит некоторые ресурсы, я знаю, но мне все равно, поскольку мой код остается простым, поэтому ... 1) добавить нижний колонтитул с видимостью GONE в ваш item_layout
2) затем установите его видимым на последнем элементе
сделайте обратное для заголовка
источник
На основе решения @seb я создал подкласс RecyclerView.Adapter, который поддерживает произвольное количество верхних и нижних колонтитулов.
https://gist.github.com/mheras/0908873267def75dc746
Хотя кажется, что это решение, я также считаю, что этим должен управлять LayoutManager. К сожалению, он мне нужен сейчас, и у меня нет времени реализовать StaggeredGridLayoutManager с нуля (и даже не расширять его).
Я все еще тестирую его, но вы можете попробовать, если хотите. Пожалуйста, дайте мне знать, если у вас возникнут проблемы.
источник
Вы можете использовать viewtype для решения этой проблемы, вот моя демонстрация: https://github.com/yefengfreedom/RecyclerViewWithHeaderFooterLoadingEmptyViewErrorView
вы можете определить режим отображения вида ресайклера:
общедоступный статический финальный int MODE_DATA = 0, MODE_LOADING = 1, MODE_ERROR = 2, MODE_EMPTY = 3, MODE_HEADER_VIEW = 4, MODE_FOOTER_VIEW = 5;
2. переопределить метод getItemViewType
3. переопределить метод getItemCount
4. переопределить метод onCreateViewHolder. создать держатель представления по viewType
5. Отмените метод onBindViewHolder. привязать данные по viewType
источник
Вы можете использовать библиотеку SectionedRecyclerViewAdapter, чтобы сгруппировать свои элементы в разделы и добавить заголовок к каждому разделу, как на изображении ниже:
Сначала вы создаете свой класс раздела:
Затем вы настраиваете RecyclerView со своими разделами и меняете SpanSize заголовков с помощью GridLayoutManager:
источник
Я знаю, что опаздываю, но только недавно мне удалось реализовать такой "addHeader" в адаптере. В моем проекте FlexibleAdapter вы можете вызвать
setHeader
элемент Sectionable , а затем позвонитьshowAllHeaders
. Если вам нужен только 1 заголовок, тогда у первого элемента должен быть заголовок. Если вы удалите этот элемент, заголовок автоматически будет связан со следующим.К сожалению, нижние колонтитулы не покрыты (пока).
FlexibleAdapter позволяет вам делать гораздо больше, чем просто создавать заголовки / разделы. Вам действительно стоит взглянуть: https://github.com/davideas/F flexibleAdapter .
источник
Я бы просто добавил альтернативу всем этим реализациям HeaderRecyclerViewAdapter. CompoundAdapter:
https://github.com/negusoft/CompoundAdapter-android
Это более гибкий подход, поскольку вы можете создать группу адаптеров из адаптеров. Для примера заголовка используйте ваш адаптер как есть, вместе с адаптером, содержащим один элемент для заголовка:
Он довольно простой и читаемый. Вы можете легко реализовать более сложный адаптер, используя тот же принцип.
источник
recyclerview:1.2.0
представляет класс ConcatAdapter, который объединяет несколько адаптеров в один. Таким образом, он позволяет создавать отдельные адаптеры верхнего / нижнего колонтитула и повторно использовать их в нескольких списках.Взгляните на анонсирующую статью . Он содержит образец того, как отображать прогресс загрузки в верхнем и нижнем колонтитулах с помощью
ConcatAdapter
.На данный момент, когда я публикую этот ответ, версия
1.2.0
библиотеки находится в альфа-стадии, поэтому api может измениться. Вы можете проверить статус здесь .источник