web-dev-qa-db-fra.com

En-tête et pied de page RecyclerView

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

49
Sandra

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.

50
Bronx

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

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:

Preview

8
lopez.mikhael

Pour les en-têtes LinearView sectionnés avec des éléments GridView dans Recyclerview: -

Vérifier SectionedGridRecyclerViewAdapter

enter image description here

2
Harpreet

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();
2
F.Will

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.

2
Raktim Bhattacharya

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" />
1
lenhuy2106

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.

1
Xiong

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))
1
Sean Blahovici

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

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:

enter image description here

1) Créez une classe de section personnalisée:

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) Créez un ViewHolder personnalisé pour les éléments:

class MyItemViewHolder extends RecyclerView.ViewHolder {

    private final TextView tvItem;

    public MyItemViewHolder(View itemView) {
        super(itemView);

        tvItem = (TextView) itemView.findViewById(R.id.tvItem);
    }
}

3) Configurez votre ReclyclerView avec 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);
1
Gustavo