基于前面的博文给RecyclerView添加Header,给RecyclerView添加多个Header
通过上节的内容,我们知道了给RecyclerView(GridLayoutManager)添加Header的方法
1.首先初始化了一个HeaderView用于下拉刷新使用并且将这个下拉刷新的布局添加到头布局
/** * 初始化头布局 */ private void initHeaderView() { header = RecyclerViewHeader.fromXml(getContext(), R.layout.refresh_header); // 添加HeaderView this.addHeaderView(header); tvTitle = (TextView) header.findViewById(R.id.tv_title); tvTime = (TextView) header.findViewById(R.id.tv_time); ivArrow = (ImageView) header.findViewById(R.id.iv_arr); pbProgress = (ProgressBar) header.findViewById(R.id.pb_progress); header.measure(0, 0); headerHeight = header.getMeasuredHeight(); // 隐藏头布局 header.setPadding(0, -headerHeight, 0, 0); // 负的值就能够让控件向上移动了 initArrowAnim(); // 初始化箭头动画 // 更新最后刷新的时间 tvTime.setText("最后刷新时间" + getCurrentTime()); }
2.在添加头布局的时候,首先先是将原先拥有的HeaderView全部都清除了,接着再将需要添加的View添加进去,值得注意的是,就是这个clear操作导致了我们自己自定义的addHeaderView方法只能够添加一个HeaderView
/** * 添加头布局 * * @param view */ public void addHeaderView(View view) { mHeaderViews.clear(); mHeaderViews.add(view); if (mAdapter != null) { if (!(mAdapter instanceof RecyclerWrapAdapter)) { mAdapter = new RecyclerWrapAdapter(mHeaderViews, mFooterViews, mAdapter); mAdapter.notifyDataSetChanged(); } } }
3.在addHeaderView中实例化RecyclerWrapAdapter,这个RecyclerWrapAdapter就是整个自定义RecyclerView中最核心的部分,我们挑选最重要的地方来看
@Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { if (viewType == RecyclerView.INVALID_TYPE) { return new HeaderViewHolder(mHeaderViews.get(0)); // 将第一个HeaderView封装 } else if (viewType == RecyclerView.INVALID_TYPE - 2) { return new HeaderViewHolder(mFooterViews.get(0)); // 将FooterView封装 } return mAdapter.onCreateViewHolder(parent, viewType); }
@Override public int getItemViewType(int position) { if (mCurrentPosition == -1) { mCurrentPosition = position; // 这是第一个HeaderView } int numHeaders = getHeadersCount(); if (position < numHeaders) { return RecyclerView.INVALID_TYPE; // 这是第一个HeaderView所占用的空间 } int adjPosition = position - numHeaders; int adapterCount = 0; if (mAdapter != null) { adapterCount = mAdapter.getItemCount(); if (adjPosition < adapterCount) { return mAdapter.getItemViewType(adjPosition); } } return RecyclerView.INVALID_TYPE - 2; // 说明是Footer的所占用的空间 }
这两段代码就是最重要的地方,我们会发现,getViewType返回的值被引用成了onCreateViewHolder的参数所以我们如果想要添加多个HeaderView就需要在这里入手。
添加多个HeaderView的具体方法:
1.我们将RecyclerWrapAdapter中的核心方法修改下,修改成可以添加两个HeaderView的
@Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { if (viewType == RecyclerView.INVALID_TYPE) { return new HeaderViewHolder(mHeaderViews.get(0)); // 将第一个HeaderView封装 } else if(viewType == RecyclerView.INVALID_TYPE - 1){ return new HeaderViewHolder(mHeaderViews.get(1)); // 将第二个HeaderView封装 } else if (viewType == RecyclerView.INVALID_TYPE - 2) { return new HeaderViewHolder(mFooterViews.get(0)); // 将FooterView封装 } return mAdapter.onCreateViewHolder(parent, viewType); }
@Override public int getItemViewType(int position) { if (mCurrentPosition == -1) { mCurrentPosition = position; // 这是第一个HeaderView } int numHeaders = getHeadersCount(); if (position < numHeaders) { if (position != mCurrentPosition) { // 这是第二个HeaderView return RecyclerView.INVALID_TYPE - 1; // 这是第二个HeaderView所占用的空间 } return RecyclerView.INVALID_TYPE; // 这是第一个HeaderView所占用的空间 } int adjPosition = position - numHeaders; int adapterCount = 0; if (mAdapter != null) { adapterCount = mAdapter.getItemCount(); if (adjPosition < adapterCount) { return mAdapter.getItemViewType(adjPosition); } } return RecyclerView.INVALID_TYPE - 2; // 说明是Footer的所占用的空间 }
2.光在RecyclerWrapAdapter里改还不够,还记得addHeaderView方法的第一行代码mHeaderView.clear();这段代码就从源头上将添加多个HeaderVIew的源头给堵住了,所以,如果我们需要添加多个HeaderView就需要将这段代码删掉。
// mHeaderViews.clear();
然后再运行下,就可以发现两个HeaderView就成功添加了!
下面附上RecyclerWrapAdapter 的源码:
package com.deltalab.urecommend.adapter.friend_pager; import android.support.v7.widget.GridLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.View; import android.view.ViewGroup; import com.deltalab.urecommend.adapter.base.WrapperAdapter; import java.util.ArrayList; /** * Created by asus on 2016/10/14. * 添加了headerView和footerView的布局适配器 * 模仿ListView里addHeader的HeaderViewListAdapter * * @author Administrator * @time 2016/10/14 16:54 */ public class RecyclerWrapAdapter extends RecyclerView.Adapter implements WrapperAdapter { private RecyclerView.Adapter mAdapter; private ArrayList<View> mHeaderViews; private ArrayList<View> mFooterViews; private int mCurrentPosition = -1; static final ArrayList<View> EMPTY_INFO_LIST = new ArrayList<View>(); public RecyclerWrapAdapter(ArrayList<View> mHeaderViews, ArrayList<View> mFooterViews, RecyclerView.Adapter mAdapter) { this.mAdapter = mAdapter; if (mHeaderViews == null) { this.mHeaderViews = EMPTY_INFO_LIST; } else { this.mHeaderViews = mHeaderViews; } if (mFooterViews == null) { this.mFooterViews = EMPTY_INFO_LIST; } else { this.mFooterViews = mFooterViews; } } /** * 获取头布局的数量 * * @return */ public int getHeadersCount() { return mHeaderViews.size(); } public int getFootersCount() { return mFooterViews.size(); } /** * 把View直接封装在ViewHolder中,然后我们面向的是ViewHolder这个实例 * 如果是Header、Footer则使用HeaderViewHolder封装 * 如果是其他的就不变 * * @param parent * @param viewType * @return */ @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { if (viewType == RecyclerView.INVALID_TYPE) { return new HeaderViewHolder(mHeaderViews.get(0)); // 将第一个HeaderView封装 } else if(viewType == RecyclerView.INVALID_TYPE - 1){ return new HeaderViewHolder(mHeaderViews.get(1)); // 将第二个HeaderView封装 } else if (viewType == RecyclerView.INVALID_TYPE - 2) { return new HeaderViewHolder(mFooterViews.get(0)); // 将FooterView封装 } return mAdapter.onCreateViewHolder(parent, viewType); } /** * 用于适配渲染数据到View中。方法提供给你了一个viewHolder,而不是原来的convertView。 * * @param holder * @param position */ @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { // Header int numHeaders = getHeadersCount(); if (position < numHeaders) { return; } // Adapter int adjPosition = position - numHeaders; int adapterCount = 0; if (mAdapter != null) { adapterCount = mAdapter.getItemCount(); if (adjPosition < adapterCount) { mAdapter.onBindViewHolder(holder, adjPosition); return; } } } /** * 将Header、Footer挂靠到RecyclerView * * @param recyclerView */ @Override public void onAttachedToRecyclerView(RecyclerView recyclerView) { super.onAttachedToRecyclerView(recyclerView); RecyclerView.LayoutManager manager = recyclerView.getLayoutManager(); if (manager instanceof GridLayoutManager) { // 布局是GridLayoutManager所管理 final GridLayoutManager gridLayoutManager = (GridLayoutManager) manager; gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { @Override public int getSpanSize(int position) { // 如果是Header、Footer的对象则占据spanCount的位置,否则就只占用1个位置 return (isHeader(position) || isFooter(position)) ? gridLayoutManager .getSpanCount() : 1; } }); } } /** * 判断是否是Header的位置 * 如果是Header的则返回true否则返回false * * @param position * @return */ public boolean isHeader(int position) { return position >= 0 && position < mHeaderViews.size(); } /** * 判断是否是Footer的位置 * 如果是Footer的位置则返回true否则返回false * * @param position * @return */ public boolean isFooter(int position) { return position < getItemCount() && position >= getItemCount() - mFooterViews.size(); } @Override public int getItemCount() { if (mAdapter != null) { return getHeadersCount() + getFootersCount() + mAdapter.getItemCount(); } else { return getHeadersCount() + getFootersCount(); } } @Override public int getItemViewType(int position) { if (mCurrentPosition == -1) { mCurrentPosition = position; // 这是第一个HeaderView } int numHeaders = getHeadersCount(); if (position < numHeaders) { if (position != mCurrentPosition) { // 这是第二个HeaderView return RecyclerView.INVALID_TYPE - 1; // 这是第二个HeaderView所占用的空间 } return RecyclerView.INVALID_TYPE; // 这是第一个HeaderView所占用的空间 } int adjPosition = position - numHeaders; int adapterCount = 0; if (mAdapter != null) { adapterCount = mAdapter.getItemCount(); if (adjPosition < adapterCount) { return mAdapter.getItemViewType(adjPosition); } } return RecyclerView.INVALID_TYPE - 2; // 说明是Footer的所占用的空间 } @Override public long getItemId(int position) { int numHeaders = getHeadersCount(); if (mAdapter != null && position >= numHeaders) { int adjPosition = position - numHeaders; int adapterCount = mAdapter.getItemCount(); if (adjPosition < adapterCount) { return mAdapter.getItemId(adjPosition); // 不是Header和Footer则返回其itemId } } return -1; } @Override public RecyclerView.Adapter getWrapperAdapter() { return mAdapter; } private static class HeaderViewHolder extends RecyclerView.ViewHolder { public HeaderViewHolder(View itemView) { super(itemView); } } }
相关推荐
本教程将详细讲解如何在RecyclerView中添加Header和Footer,这对于构建复杂布局,如添加广告条或者底部操作按钮是非常实用的。 首先,我们需要理解RecyclerView的基本架构。RecyclerView由Adapter和LayoutManager两...
以上就是对RecyclerView进行封装,实现加载更多和添加Header、Footer的主要步骤。在LoadMoreRecyclerView-master项目中,你将会看到具体实现这些功能的代码,包括Adapter的实现、滚动监听、UI反馈以及错误处理。通过...
- 创建对应的ViewHolder类,例如HeaderViewHolder、FooterViewHolder和ItemViewHolder,分别处理Header、Footer和列表项的视图绑定。 3. **添加Header和Footer** - 在Adapter的`onCreateViewHolder`方法中,根据`...
- `getItemViewType(int position)`:根据位置返回viewType,这里需要添加逻辑来区分Header、Footer和数据项。 - `onCreateViewHolder(ViewGroup parent, int viewType)`:根据viewType创建ViewHolder实例,如果...
本资源提供了一个实现RecyclerView的全面功能的源码示例,包括添加Header和Footer视图,以及集成下拉刷新和上拉加载更多的功能。 一、RecyclerView基础 RecyclerView的核心在于其适配器(RecyclerView.Adapter)和...
然而,原生的RecyclerView仅提供基本的列表展示功能,无法直接实现页眉(Header)和页脚(Footer)的添加。为了解决这个问题,开发者们通常会采用自定义适配器或者第三方库,如`SectionedRecyclerView`。本篇文章将...
本篇将详细讲解如何在RecyclerView中添加头布局(header)和尾布局(footer)。 首先,理解RecyclerView的基本结构。RecyclerView由Adapter、LayoutManager和ViewHolder三部分组成。Adapter是数据源,负责处理数据...
RecyclerView支持添加Header和Footer,这在实现如下拉刷新、上拉加载更多等功能时非常有用。可以通过在Adapter的构造函数中传递Header和Footer的视图,然后在`getItemViewType()`方法中进行区分。 9. **状态保存和...
13. **Header和Footer** 要在RecyclerView中添加头部和尾部,可以利用`addHeaderView()`和`addFooterView()`方法,但需要注意它们不直接支持,需要在Adapter中进行处理。 14. **嵌套滚动** RecyclerView支持嵌套...
4. **Header和Footer**:有时我们需要在列表的顶部或底部添加固定项,可以使用预加载方法在RecyclerView的开始或结束位置添加Header和Footer。 5. **自定义动画**:通过设置ItemAnimator,可以为RecyclerView添加...
- 尾部布局(Footer Layout)则常用于显示一些附加信息,如加载更多按钮、版权信息等。类似地,我们可以创建一个自定义ViewGroup并将其添加到Adapter的底部。 2. **空布局(Empty View)**: - 当RecyclerView...
你可以根据需求添加Header、Footer,或者使用GridLayoutManager、StaggeredGridLayoutManager等其他布局管理器。另外,还可以实现Item点击事件、动画效果以及下拉刷新和上拉加载更多功能。 对于更复杂的需求,例如...
在项目中,还展示了如何添加Header和Footer到RecyclerView。这通常用于显示额外的信息或操作,比如加载更多。可以使用`addHeaderView()`和`addFooterView()`方法,但需要注意它们不直接属于RecyclerView的API,而是...
在Android开发中,RecyclerView是一个非常重要的视图组件,它...在实际项目中,你还可以根据需要扩展功能,例如添加Footer、实现滑动加载更多等。记得在编写代码时遵循良好的编程实践,确保代码的可读性和可维护性。
2. 使用Header/Footer功能,可以在列表的开头或结尾添加固定视图。 3. 实现Drag & Drop功能,允许用户重新排列列表项。 4. 使用SnapHelper实现列表项自动吸附效果,如两端对齐、居中对齐等。 5. 结合Paging库实现...
3. Header/Footer:在RecyclerView中添加头部或尾部视图。 通过以上讲解,我们了解了RecyclerView的基本概念、使用方法以及一些高级特性。实践中,开发者可以根据需求灵活运用这些知识点,打造高效且用户友好的列表...
RecyclerView可以通过设置Header和Footer来扩展其功能,比如添加广告栏或加载更多按钮。 6. **嵌套滚动**: RecyclerView可以与其他可滚动视图(如NestedScrollView)实现嵌套滚动,协同处理触摸事件。 7. **...
RecyclerView还可以添加Header和Footer,以及ItemDecoration来实现分割线。通过addItemDecoration()方法添加自定义的ItemDecoration,可以实现定制的分隔线样式。 7. **点击事件处理** 在ViewHolder中,我们可以...
- Header/Footer支持:可以通过在Adapter的dataList中添加特殊标记来实现头部和尾部的添加。 - 多类型列表:通过在Adapter中判断数据类型并返回不同ViewHolder,可以实现一个列表显示多种视图。 - 动态加载更多:...
除了基本的列表项,还可以添加头部视图(header view)和尾部视图(footer view)。这通常通过在适配器中处理逻辑实现,比如在onCreateViewHolder()中返回不同类型的ViewHolder。 十、多视图类型 RecyclerView还...