RecyclerView верхний и нижний колонтитулы
Возможно, этот вопрос задавался ранее, но я не мог найти точного ответа или решения. Я начал использовать RecyclerView и реализовал его с помощью LinearLayoutManager. Теперь я хочу добавить пользовательские элементы верхнего и нижнего колонтитула, которые отличаются от остальных элементов моего RecyclerView. Верхний и нижний колонтитулы не должны быть липкими, я хочу, чтобы они прокручивались вместе с остальными элементами. Может кто-нибудь привести пример, как это сделать, или просто поделиться идеями. Я буду очень признателен за это. Спасибо
10 ответов
В вашем адаптере добавьте этот класс:
private class VIEW_TYPES {
public static final int Header = 1;
public static final int Normal = 2;
public static final int Footer = 3;
}
затем переопределите следующий метод следующим образом:
@Override
public int getItemViewType(int position) {
if(items.get(position).isHeader)
return VIEW_TYPES.Header;
else if(items.get(position).isFooter)
return VIEW_TYPES.Footer;
else
return VIEW_TYPES.Normal;
}
Теперь в методе onCreateViewHolder надуйте ваш макет на основе типа представления:
@Override
public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View rowView;
switch (i)
{
case VIEW_TYPES.Normal:
rowView=LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.normal, viewGroup, false);
break;
case VIEW_TYPES.Header:
rowView=LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.header, viewGroup, false);
break;
case VIEW_TYPES.Footer:
rowView=LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.footer, viewGroup, false);
break;
default:
rowView=LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.normal, viewGroup, false);
break;
}
return new ViewHolder (rowView);
}
Надеюсь, это поможет.
Это очень легко с ItemDecorations и без изменения любого другого кода:
recyclerView.addItemDecoration(new HeaderDecoration(this,
recyclerView, R.layout.test_header));
Оставьте немного места для рисования, надуйте макет, который вы хотите нарисовать, и нарисуйте его в зарезервированном пространстве.
Код для украшения:
public class HeaderDecoration extends RecyclerView.ItemDecoration {
private View mLayout;
public HeaderDecoration(final Context context, RecyclerView parent, @LayoutRes int resId) {
// inflate and measure the layout
mLayout = LayoutInflater.from(context).inflate(resId, parent, false);
mLayout.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
}
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
super.onDraw(c, parent, state);
// layout basically just gets drawn on the reserved space on top of the first view
mLayout.layout(parent.getLeft(), 0, parent.getRight(), mLayout.getMeasuredHeight());
for (int i = 0; i < parent.getChildCount(); i++) {
View view = parent.getChildAt(i);
if (parent.getChildAdapterPosition(view) == 0) {
c.save();
final int height = mLayout.getMeasuredHeight();
final int top = view.getTop() - height;
c.translate(0, top);
mLayout.draw(c);
c.restore();
break;
}
}
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
if (parent.getChildAdapterPosition(view) == 0) {
outRect.set(0, mLayout.getMeasuredHeight(), 0, 0);
} else {
outRect.setEmpty();
}
}
}
Если все, что вам нужно, это пустой верхний и нижний колонтитулы, вот очень простой способ добиться этого (написанный на Kotlin):
class HeaderFooterDecoration(private val headerHeight: Int, private val footerHeight: Int) : RecyclerView.ItemDecoration() {
override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {
val adapter = parent.adapter ?: return
when (parent.getChildAdapterPosition(view)) {
0 -> outRect.top = headerHeight
adapter.itemCount - 1 -> outRect.bottom = footerHeight
else -> outRect.set(0, 0, 0, 0)
}
}
}
Назовите это так:
recyclerView.addItemDecoration(HeaderFooterDecoration(headerHeightPx, footerHeightPx))
Recyclerview :1.2.0 представляет ConcatAdapter
ConcatAdapter - это новый адаптер RecyclerView, который может линейно комбинировать несколько адаптеров.
Как использовать ConcatAdapter?
добавьте следующую зависимость в свой build.gradle
файл
androidx.recyclerview:recyclerview:1.2.0-alpha04
Затем, если у вас несколько адаптеров, вы можете легко объединить их, используя
MyAdapter adapter1 = ...;
AnotherAdapter adapter2 = ...;
ConcatAdapter merged = new ConcatAdapter(adapter1, adapter2);
recyclerView.setAdapter(merged);
В приведенном выше примере ConcatAdapter представит элементы из адаптера 1, за которым следует адаптер 2.
Здесь вы можете найти полную документацию.
Полный рабочий образец можно найти здесь.
Прочтите эту статью для получения дополнительной информации.
Здесь вы можете найти исходный код.
Вы можете использовать эту библиотеку GitHub], чтобы добавить верхний или нижний колонтитул к вашему RecyclerView
самым простым способом
Вам нужно добавить библиотеку HFRecyclerView в ваш проект или вы также можете получить ее из Gradle:
compile 'com.mikhaellopez:hfrecyclerview:1.0.0'
Эта библиотека основана на работе @hister
Это результат в изображении:
Я бы предложил не настраивать rv адаптер.
Оставьте все как есть... в макете элемента rv просто добавьте нижний колонтитул с макетом и уберите видимость.
Затем, когда вы дойдете до последнего элемента в адаптере... сделайте его видимым.
и когда вы попробуете это, убедитесь, что вы добавили это к вашему адаптеру rv.
@Override
public void onBindViewHolder(final PersonViewHolder personViewHolder, int i) {
if(i==List.size()) // Last item in recycle view
personViewHolder.tv_footer.setVisibility(VISIBLE);// Make footer visible now }
@Override
public int getItemViewType(int position) {
return position;
}
Сделайте то же самое для Заголовка. Здесь я ==0 // первый элемент списка
Самое простое решение для меня.
Здесь какой-то заголовок itemdecoration для recyclerview
с некоторыми изменениями вы можете перейти в нижний колонтитул
public class HeaderItemDecoration extends RecyclerView.ItemDecoration {
private View customView;
public HeaderItemDecoration(View view) {
this.customView = view;
}
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
super.onDraw(c, parent, state);
customView.layout(parent.getLeft(), 0, parent.getRight(), customView.getMeasuredHeight());
for (int i = 0; i < parent.getChildCount(); i++) {
View view = parent.getChildAt(i);
if (parent.getChildAdapterPosition(view) == 0) {
c.save();
final int height = customView.getMeasuredHeight();
final int top = view.getTop() - height;
c.translate(0, top);
customView.draw(c);
c.restore();
break;
}
}
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
if (parent.getChildAdapterPosition(view) == 0) {
customView.measure(View.MeasureSpec.makeMeasureSpec(parent.getMeasuredWidth(), View.MeasureSpec.AT_MOST),
View.MeasureSpec.makeMeasureSpec(parent.getMeasuredHeight(), View.MeasureSpec.AT_MOST));
outRect.set(0, customView.getMeasuredHeight(), 0, 0);
} else {
outRect.setEmpty();
}
}
}
Еще один способ - обернуть заголовок и обзор рейка в координатный макет:
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:elevation="0dp">
<View
android:id="@+id/header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_scrollFlags="scroll" />
</android.support.design.widget.AppBarLayout>
<android.support.v7.widget.RecyclerView
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
Нажмите здесь Я сделал расширение RecyclerView.Adapter. Легко добавить верхний и нижний колонтитулы.
class HFAdapter extends HFRecyclerViewAdapter<String, HFAdapter.DataViewHolder>{
public HFAdapter(Context context) {
super(context);
}
@Override
public DataViewHolder onCreateDataItemViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.data_item, parent, false);
return new DataViewHolder(v);
}
@Override
public void onBindDataItemViewHolder(DataViewHolder holder, int position) {
holder.itemTv.setText(getData().get(position));
}
class DataViewHolder extends RecyclerView.ViewHolder{
TextView itemTv;
public DataViewHolder(View itemView) {
super(itemView);
itemTv = (TextView)itemView.findViewById(R.id.itemTv);
}
}
}
//add header
View headerView = LayoutInflater.from(this).inflate(R.layout.header, recyclerView, false);
hfAdapter.setHeaderView(headerView);
//add footer
View footerView = LayoutInflater.from(this).inflate(R.layout.footer, recyclerView, false);
hfAdapter.setFooterView(footerView);
//remove
hfAdapter.removeHeader();
hfAdapter.removeFooter();
Для секционных заголовков LinearView с элементами GridView в Recyclerview:-
Проверьте SectionedGridRecyclerViewAdapter
Вы можете использовать библиотеку https://github.com/luizgrp/SectionedRecyclerViewAdapter, в ней есть понятие "Разделы", где у какого Раздела есть Верхний колонтитул, Нижний колонтитул и Содержимое (список элементов). В вашем случае вам может понадобиться только один раздел, но вы можете иметь много:
1) Создайте собственный класс раздела:
class MySection extends StatelessSection {
List<String> myList = Arrays.asList(new String[] {"Item1", "Item2", "Item3" });
public MySection() {
// call constructor with layout resources for this Section header, footer and items
super(R.layout.section_header, R.layout.section_footer, R.layout.section_item);
}
@Override
public int getContentItemsTotal() {
return myList.size(); // number of items of this section
}
@Override
public RecyclerView.ViewHolder getItemViewHolder(View view) {
// return a custom instance of ViewHolder for the items of this section
return new MyItemViewHolder(view);
}
@Override
public void onBindItemViewHolder(RecyclerView.ViewHolder holder, int position) {
MyItemViewHolder itemHolder = (MyItemViewHolder) holder;
// bind your view here
itemHolder.tvItem.setText(myList.get(position));
}
}
2) Создайте пользовательский ViewHolder для элементов:
class MyItemViewHolder extends RecyclerView.ViewHolder {
private final TextView tvItem;
public MyItemViewHolder(View itemView) {
super(itemView);
tvItem = (TextView) itemView.findViewById(R.id.tvItem);
}
}
3) Настройте ваш ReclyclerView с помощью SectionedRecyclerViewAdapter
// Create an instance of SectionedRecyclerViewAdapter
SectionedRecyclerViewAdapter sectionAdapter = new SectionedRecyclerViewAdapter();
MySection mySection = new MySection();
// Add your Sections
sectionAdapter.addSection(mySection);
// Set up your RecyclerView with the SectionedRecyclerViewAdapter
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerview);
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
recyclerView.setAdapter(sectionAdapter);
Может быть, GroupAdapter это то, что вы хотите.
Специализированный RecyclerView.Adapter, который представляет данные из последовательности RecyclerView.Adapter. Последовательность является статической, но каждый адаптер может быть представлен в виде нуля или более элементов. Дочерний адаптер может безопасно использовать ViewType. Кроме того, мы можем добавить addHeaderView или addFooterView как ListView.