Android RecyclerView 页眉和页脚

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/26585941/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 11:54:48  来源:igfitidea点击:

RecyclerView header and footer

androidheaderfooterandroid-5.0-lollipopandroid-recyclerview

提问by Sandra

Maybe this question has been asked before, but I could not seem to find a precise answer or solution. I started using the RecyclerView, and I implemented it using the LinearLayoutManager. Now I want to add custom header and footer items, that differ from the rest of the items in my RecyclerView. The header and footer should not be sticky, I want them to scroll with the rest of the items. Can somebody point out some example how to do this or just share ideas. I will appreciate it very much. Thx

也许之前已经问过这个问题,但我似乎找不到确切的答案或解决方案。我开始使用 RecyclerView,并使用 LinearLayoutManager 实现它。现在我想添加自定义页眉和页脚项目,它们与我的 RecyclerView 中的其他项目不同。页眉和页脚不应该是粘性的,我希望它们与其余项目一起滚动。有人可以指出一些如何做到这一点的例子或只是分享想法。我会很感激的。谢谢

回答by Bronx

in your adapter add this class:

在您的适配器中添加此类:

private class VIEW_TYPES {
        public static final int Header = 1;
        public static final int Normal = 2;
        public static final int Footer = 3;
}

then Override the following method like this:

然后像这样覆盖以下方法:

@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;

}

Now in the onCreateViewHolder method inflate your layout based on the view type::

现在在 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);
}

Now in the onBindViewHolder method bind your layout based on the view holder:

现在在 onBindViewHolder 方法中,根据视图持有者绑定您的布局:

@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;

        }

    }

Hope this can help.

希望这能有所帮助。

回答by David Medenjak

This is very easy with ItemDecorations and without modifying any other code:

使用 ItemDecorations 这很容易,无需修改任何其他代码:

recyclerView.addItemDecoration(new HeaderDecoration(this,
                               recyclerView,  R.layout.test_header));

Reserve some space for drawing, inflate the layout you want drawn and draw it in the reserved space.

预留一些空间进行绘图,将要绘制的布局膨胀并在保留空间中绘制。

The code for the Decoration:

装饰代码:

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

回答by lopez.mikhael

You can use this GitHub] library to add a Header or Footer to your RecyclerViewin the simplest way possible.

您可以使用此 GitHub] 库以RecyclerView尽可能最简单的方式向您添加页眉或页脚。

You need to add the HFRecyclerViewlibrary in your project or you can also grab it from Gradle:

你需要在你的项目中添加HFRecyclerView库,或者你也可以从 Gradle 获取它:

compile 'com.mikhaellopez:hfrecyclerview:1.0.0'

This library is based on a work at @hister

该库基于@hister的作品

This is a result in image:

这是图像中的结果:

Preview

预览

回答by Sean Blahovici

If all you need is a blank header and footer, here is a very simple way to achieve this (written in Kotlin):

如果您只需要一个空白的页眉和页脚,这里有一个非常简单的方法来实现这一点(用 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)
        }
    }
}

Call it this way:

这样称呼它:

recyclerView.addItemDecoration(HeaderFooterDecoration(headerHeightPx, footerHeightPx))

回答by Raktim Bhattacharya

I would suggest not to customize rv adapater.

我建议不要自定义 rv adapater。

Keep it as it as...in your rv item layout just add the footer with the layout and set the visisbilty gone.

保持原样...在您的 rv 项目布局中,只需添加带有布局的页脚并设置可见性。

Then when you reach the last item in adapter...make it visible.

然后,当您到达适配器中的最后一项时...使其可见。

and when you try this make sure you add this to your rv adapter.

当您尝试此操作时,请确保将其添加到您的 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;
    }

Do the same for Header. Here i==0 // first item of list

对 Header 执行相同的操作。这里 i==0 // 列表的第一项

Easiest solution to me.

对我来说最简单的解决方案。

回答by F.Will

Click here. I did a extension of RecyclerView.Adapter. Easy to add header and footer.

点击这里。我做了一个 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();

回答by Harpreet

For Sectioned LinearView headings with GridView items in Recyclerview:-

对于 Recyclerview 中带有 GridView 项目的分段 LinearView 标题:-

Check SectionedGridRecyclerViewAdapter

检查SectionedGridRecyclerViewAdapter

enter image description here

在此处输入图片说明

回答by Trunks ssj

here some header itemdecoration for recyclerview

这里有一些用于 recyclerview 的标题项装饰

withsome modification you can change to footer

稍加修改,您可以更改为页脚

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

回答by Gustavo

You can use the library SectionedRecyclerViewAdapter, it has the concept of "Sections", where which Section has a Header, Footer and Content (list of items). In your case you might only need one Section but you can have many:

您可以使用库SectionedRecyclerViewAdapter,它有“节”的概念,其中节有页眉、页脚和内容(项目列表)。在您的情况下,您可能只需要一个部分,但您可以有多个:

enter image description here

在此处输入图片说明

1) Create a custom Section class:

1)创建自定义Section类:

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) Create a custom ViewHolder for the items:

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) Set up your ReclyclerView with the SectionedRecyclerViewAdapter

3) 使用 SectionedRecyclerViewAdapter 设置您的 ReclyclerView

// 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);

回答by Xiong

May be GroupAdapteris what you want.

可能GroupAdapter是你想要的。

A specialized RecyclerView.Adapter that presents data from a sequence of RecyclerView.Adapter. The sequence is static but each adapter can be presented in zero or more item views. The child adapter can use ViewType safely. In addition, we can addHeaderView or addFooterView like ListView.

一个专门的 RecyclerView.Adapter,用于呈现来自 RecyclerView.Adapter 序列的数据。序列是静态的,但每个适配器都可以在零个或多个项目视图中呈现。子适配器可以安全地使用 ViewType。另外,我们可以像ListView一样addHeaderView或者addFooterView。