Peut-être que cette question a déjà été posée, mais je n’ai pas semblé pouvoir trouver une réponse ou une solution précise. J'ai commencé à utiliser RecyclerView et je l'ai implémenté à l'aide de LinearLayoutManager. Maintenant, je souhaite ajouter des éléments d’en-tête et de pied de page personnalisés, qui diffèrent du reste des éléments de mon RecyclerView. L'en-tête et le pied de page ne doivent pas être collants, je veux qu'ils défilent avec le reste des éléments. Quelqu'un peut-il indiquer un exemple de la façon de procéder ou simplement partager des idées? Je l'apprécierai beaucoup. THX
dans votre adaptateur, ajoutez cette classe:
private class VIEW_TYPES {
public static final int Header = 1;
public static final int Normal = 2;
public static final int Footer = 3;
}
puis substituez la méthode suivante comme ceci:
@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;
}
Maintenant, dans la méthode onCreateViewHolder, gonflez votre mise en page en fonction du type de vue:
@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);
}
Maintenant, dans la méthode onBindViewHolder, liez votre mise en page en fonction du détenteur de la vue:
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position) {
int viewType = getItemViewType(position);
switch(viewType) {
case VIEW_TYPES.Header: // handle row header
break;
case VIEW_TYPES.Footer: // handle row footer
break;
case VIEW_TYPES.Normal: // handle row item
break;
}
}
J'espère que cela peut aider.
C'est très facile avec ItemDecorations et sans modifier aucun autre code:
recyclerView.addItemDecoration(new HeaderDecoration(this,
recyclerView, R.layout.test_header));
Réservez un espace pour dessiner, gonflez la mise en page souhaitée et dessinez-la dans l'espace réservé.
Le code de la décoration:
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();
}
}
}
Vous pouvez utiliser cette bibliothèque GitHub] pour ajouter un en-tête ou un pied de page à votre RecyclerView
de la manière la plus simple possible.
Vous devez ajouter la bibliothèque HFRecyclerView dans votre projet ou vous pouvez également la récupérer dans Gradle:
compile 'com.mikhaellopez:hfrecyclerview:1.0.0'
Cette bibliothèque est basée sur un travail à @ hister
Ceci est un résultat dans l'image:
Pour les en-têtes LinearView sectionnés avec des éléments GridView dans Recyclerview: -
Vérifier SectionedGridRecyclerViewAdapter
Cliquez ici . J'ai fait une extension de RecyclerView.Adapter. Facile à ajouter en-tête et pied de page.
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();
Je suggérerais de ne pas personnaliser l'adaptateur de RV.
Gardez-le comme il est ... dans la disposition de votre article RV, ajoutez simplement le pied de page avec la disposition et réglez la visibilité.
Puis, lorsque vous atteignez le dernier élément de l’adaptateur, rendez-le visible.
et lorsque vous essayez ceci, assurez-vous de l'ajouter à votre adaptateur 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;
}
Faites la même chose pour Header. Ici i == 0 // premier élément de la liste
La solution la plus simple pour moi.
Une autre solution consisterait à en-tête et à une nouvelle vue d'ensemble dans coordinatorlayout:
<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" />
Peut-être GroupAdapter est ce que vous voulez.
RecyclerView.Adapter spécialisé qui présente les données d'une séquence de RecyclerView.Adapter. La séquence est statique, mais chaque adaptateur peut être présenté sous zéro ou plusieurs vues d'élément. L'adaptateur enfant peut utiliser ViewType en toute sécurité. De plus, nous pouvons ajouterHeaderView ou addFooterView comme ListView.
Si tout ce dont vous avez besoin est un en-tête et un pied de page vierges, voici un moyen très simple d'y parvenir (écrit en 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)
}
}
}
Appelez ça comme ça:
recyclerView.addItemDecoration(HeaderFooterDecoration(headerHeightPx, footerHeightPx))
voici quelques en-tête itemdecoration pour recyclerview
avec quelques modifications, vous pouvez changer en pied de page
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();
}
}
}
Vous pouvez utiliser la bibliothèque SectionedRecyclerViewAdapter , elle a le concept de "Sections", où Section a un en-tête, un pied de page et un contenu (liste d’articles). Dans votre cas, vous n’avez peut-être besoin que d’une seule section, mais vous pouvez en avoir plusieurs:
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));
}
}
class MyItemViewHolder extends RecyclerView.ViewHolder {
private final TextView tvItem;
public MyItemViewHolder(View itemView) {
super(itemView);
tvItem = (TextView) itemView.findViewById(R.id.tvItem);
}
}
// 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);