RecyclerView添加headerview和footview
来源:互联网 发布:百度洗地 知乎 编辑:程序博客网 时间:2024/05/03 23:57
随着使用的普及,RecyclerView
基本取代了listView
、gridView
等控件。
在日常开发中,有时候会使用到headerview
、footview
,但是RecyclerView
的API并没有提供类似于listview
的addfootview()
等放法,这种情况应该怎么处理呢?
普遍的解决方案就是通过指定adapter
的itemType
来区分将其与内容区域区分开。
本篇文章参考了其他博主的文章,并将一些细节部分进行了完善
鸿洋的博客:
Android 优雅的为RecyclerView添加HeaderView和FooterView
亓斌的博客
RecyclerView添加Header的正确方式
这是鸿洋封装的外部wrapper对象,很完善
public class HeaderAndFooterWrapper<T> extends RecyclerView.Adapter<RecyclerView.ViewHolder> { private static final int BASE_ITEM_TYPE_HEADER = 100000; private static final int BASE_ITEM_TYPE_FOOTER = 200000; private SparseArrayCompat<View> mHeaderViews = new SparseArrayCompat<>(); private SparseArrayCompat<View> mFootViews = new SparseArrayCompat<>(); private RecyclerView.Adapter mInnerAdapter; public HeaderAndFooterWrapper(RecyclerView.Adapter adapter) { mInnerAdapter = adapter; } @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { if (mHeaderViews.get(viewType) != null) { BaseViewHolder holder = BaseViewHolder.createViewHolder(parent.getContext(), mHeaderViews.get(viewType)); return holder; } else if (mFootViews.get(viewType) != null) { BaseViewHolder holder = BaseViewHolder.createViewHolder(parent.getContext(), mFootViews.get(viewType)); return holder; } return mInnerAdapter.onCreateViewHolder(parent, viewType); } @Override public int getItemViewType(int position) { if (isHeaderViewPos(position)) { return mHeaderViews.keyAt(position); } else if (isFooterViewPos(position)) { return mFootViews.keyAt(position - getHeadersCount() - getRealItemCount()); } return mInnerAdapter.getItemViewType(position - getHeadersCount()); } private int getRealItemCount() { return mInnerAdapter.getItemCount(); } @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { if (isHeaderViewPos(position)) { return; } if (isFooterViewPos(position)) { return; } mInnerAdapter.onBindViewHolder(holder, position - getHeadersCount()); } @Override public int getItemCount() { return getHeadersCount() + getFootersCount() + getRealItemCount(); } @Override public void onAttachedToRecyclerView(RecyclerView recyclerView) { WrapperUtils.onAttachedToRecyclerView(mInnerAdapter, recyclerView, new WrapperUtils.SpanSizeCallback() { @Override public int getSpanSize(GridLayoutManager layoutManager, GridLayoutManager.SpanSizeLookup oldLookup, int position) { int viewType = getItemViewType(position); if (mHeaderViews.get(viewType) != null) { return layoutManager.getSpanCount(); } else if (mFootViews.get(viewType) != null) { return layoutManager.getSpanCount(); } if (oldLookup != null) return oldLookup.getSpanSize(position); return 1; } }); } @Override public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) { mInnerAdapter.onViewAttachedToWindow(holder); int position = holder.getLayoutPosition(); if (isHeaderViewPos(position) || isFooterViewPos(position)) { WrapperUtils.setFullSpan(holder); } } private boolean isHeaderViewPos(int position) { return position < getHeadersCount(); } private boolean isFooterViewPos(int position) { return position >= getHeadersCount() + getRealItemCount(); } public void addHeaderView(View view) { view.setTag(mHeaderViews.size() + BASE_ITEM_TYPE_HEADER); mHeaderViews.put(mHeaderViews.size() + BASE_ITEM_TYPE_HEADER, view); } public void addFootView(View view) { view.setTag(mFootViews.size() + BASE_ITEM_TYPE_FOOTER); mFootViews.put(mFootViews.size() + BASE_ITEM_TYPE_FOOTER, view); } public int getHeadersCount() { return mHeaderViews.size(); } public int getFootersCount() { return mFootViews.size(); }}
基本思路就是利用装饰者模式,不去动内部adapter
,利用wrapper
来包裹,直接加入headerView
和footerView
,利用viewtype
来与普通的item
对象作出区分。
其中的mHeaderViews
和mFootViews
都是SparseArrayCompat<View>
,SparseArrayCompat
是近期Android
推荐的类似于hashmap
的一种存储结构,特定服务于Android
,更为高效。
而mHeaderViews
和mFootViews
里的view是如何进行标识的呢,主要是根据初始定义的BASE_ITEM_TYPE_HEADER
和BASE_ITEM_TYPE_FOOTER
,两个的初始量设置的比较大,不会出现于普通视图的冲突问题。然后根据加入view时,mFootViews的元素数量和基础量相加得到每个view的位置,整体的功能就能实现了
再来看看其中的BaseViewHolder是这样的
public class BaseViewHolder extends RecyclerView.ViewHolder { protected final SparseArray<View> mViews; protected View mConvertView; private Context mContext; public BaseViewHolder(Context context, View itemView) { super(itemView); mContext = context; mViews = new SparseArray<>(); mConvertView = itemView; } public static BaseViewHolder createViewHolder(Context context, View itemView) { BaseViewHolder holder = new BaseViewHolder(context, itemView); return holder; } public static BaseViewHolder createViewHolder(Context context, ViewGroup parent, int layoutId) { View itemView = LayoutInflater.from(context).inflate(layoutId, parent, false); BaseViewHolder holder = new BaseViewHolder(context, itemView); return holder; } /** * 通过资源Id获取对应控件,如果没有,则加入views * * @param viewId 资源Id * @param <T> view * @return */ public <T extends View> T getView(int viewId) { View view = mViews.get(viewId); if (view == null) { view = mConvertView.findViewById(viewId); mViews.put(viewId, view); } return (T) view; } /** * 实现通用的属性设置方法 * * @param viewId 控件Id * @param value string value * @return */ public BaseViewHolder setText(int viewId, String value) { TextView view = getView(viewId); view.setText(value); return BaseViewHolder.this; }}
还有WrapperUtils处理的是不同layoutManager的适配问题
public class WrapperUtils{ public interface SpanSizeCallback { int getSpanSize(GridLayoutManager layoutManager , GridLayoutManager.SpanSizeLookup oldLookup, int position); } public static void onAttachedToRecyclerView(RecyclerView.Adapter innerAdapter, RecyclerView recyclerView, final SpanSizeCallback callback) { innerAdapter.onAttachedToRecyclerView(recyclerView); RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager(); if (layoutManager instanceof GridLayoutManager) { final GridLayoutManager gridLayoutManager = (GridLayoutManager) layoutManager; final GridLayoutManager.SpanSizeLookup spanSizeLookup = gridLayoutManager.getSpanSizeLookup(); gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { @Override public int getSpanSize(int position) { return callback.getSpanSize(gridLayoutManager, spanSizeLookup, position); } }); gridLayoutManager.setSpanCount(gridLayoutManager.getSpanCount()); } } public static void setFullSpan(RecyclerView.ViewHolder holder) { ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams(); if (lp != null && lp instanceof StaggeredGridLayoutManager.LayoutParams) { StaggeredGridLayoutManager.LayoutParams p = (StaggeredGridLayoutManager.LayoutParams) lp; p.setFullSpan(true); } }}
最后在activity中就可以完整使用了
写完发现用的还是鸿洋的baseAdapter系列东西,好吧,原创部分是自己的实现
源码还在更新,更新好了再上传
- RecyclerView添加headerview和footview
- 仿照Listview 优雅实现 RecyclerView的 HeaderView 和 FootView
- 为RecyclerView添加FootView和HeadView
- RecyclerView添加HeaderView和FooterView
- RecyclerView添加HeaderView和FooterView
- RecyclerView添加HeaderView和FooterView
- RecyclerView 添加headerView 和 footerView
- Android 简捷地为RecyclerView添加HeadView和FootView
- RecyclerView加载headView和footView,添加头尾布局
- RecyclerView封装--添加HeaderView和FooterView
- 在ListView中增加HeaderView和FootView
- RecyclerView(ScrollView嵌套,添加HeardView、FootView)
- Android 优雅的为RecyclerView添加HeaderView和FooterView
- Android 优雅的为RecyclerView添加HeaderView和FooterView
- Android 优雅的为RecyclerView添加HeaderView和FooterView
- Android 优雅的为RecyclerView添加HeaderView和FooterView
- Android 优雅的为RecyclerView添加HeaderView和FooterView
- Android 优雅的为RecyclerView添加HeaderView和FooterView
- final修饰符
- ssh-config配置
- YUV文件格式
- was控制台英文改成中文
- c# Datagridview控件实现指定字段查找功能【未解决】
- RecyclerView添加headerview和footview
- CAN LoopBack
- java学习笔记最难理解的多态
- 转:ASP.NET MVC:窗体身份验证及角色权限管理示例
- HDU-4135-Co-prime
- POJ2586Y2K Accounting Bug
- echo 输出带颜色方法
- 查找当前目录及其子目录下文件的行数
- NT驱动加载方式