RecyclerView with Header&Footer (只是记录,没有详细步骤)
相关知识点
- RecyclerView
- ListView的头部添加和删除
- RecyclerView和ListView的区别
核心内容
- FixedViewInfo:A class that represents a fixed view in a list, for example a header at the top or a footer at the bottom.
- 因为Recyclerview是ListView的替代品,所以他们之间应该会很接近,但是RecyclerView已经高度解耦了,所以RecyclerView并没有提供添加HeaderView和FooterView的方法,那我们如何为RecyclerView添加自己的Header和Footer呢,当然是重写喽
- RecyclerView的适配器数据和布局加载是分开的,哪有如何处理呢。
源码分析
- 因为RecyclerView都是简介或者直接继承了ViewGroup跟ListView没有半毛钱关系,所以我们就不看他们的构造函数了。
- 我们直接看他添加添加头部和尾部的方法吧:addHeaderView/addFooterView
`
public void addFooterView(View v, Object data, boolean isSelectable) {
final FixedViewInfo info = new FixedViewInfo();
info.view = v;
info.data = data;
info.isSelectable = isSelectable;
mFooterViewInfos.add(info);
mAreAllItemsSelectable &= isSelectable;
// Wrap the adapter if it wasn't already wrapped.
if (mAdapter != null) {
if (!(mAdapter instanceof HeaderViewListAdapter)) {
mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, mAdapter);
}
// In the case of re-adding a footer view, or adding one later on,
// we need to notify the observer.
if (mDataSetObserver != null) {
mDataSetObserver.onChanged();
}
}
}
`
`
public void addFooterView(View v, Object data, boolean isSelectable) {
final FixedViewInfo info = new FixedViewInfo();
info.view = v;
info.data = data;
info.isSelectable = isSelectable;
mFooterViewInfos.add(info);
mAreAllItemsSelectable &= isSelectable;
// Wrap the adapter if it wasn't already wrapped.
if (mAdapter != null) {
if (!(mAdapter instanceof HeaderViewListAdapter)) {
mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, mAdapter);
}
// In the case of re-adding a footer view, or adding one later on,
// we need to notify the observer.
if (mDataSetObserver != null) {
mDataSetObserver.onChanged();
}
}
}`
3、他的精妙指出是在addHeaderView和AddFooterView中用代理的方式,将当前的adapter和头部和底部的列表整合在了一起,所以我们的思路就是仿照ListView的这种做法,自己编写代理adapter,同时在addFooterView和AddFooterView方法中调用和使用,同时这里不要漏掉一个细节,解释listview的setAdapter方法也需要使用这种代理adapter,这样提高代码的重用,所以代理adapter里面要分别处理头部和底部以及中间内容数据。来看看ListView的代理适配器对视图加载和数据填充的getView方法吧:
在ListView中的处理
public View getView(int position, View convertView, ViewGroup parent) {
// Header (negative positions will throw an IndexOutOfBoundsException)
int numHeaders = getHeadersCount();
if (position < numHeaders) {
return mHeaderViewInfos.get(position).view;
}
// Adapter
final int adjPosition = position - numHeaders;
int adapterCount = 0;
if (mAdapter != null) {
adapterCount = mAdapter.getCount();
if (adjPosition < adapterCount) {
return mAdapter.getView(adjPosition, convertView, parent);
}
}
// Footer (off-limits positions will throw an IndexOutOfBoundsException)
return mFooterViewInfos.get(adjPosition - adapterCount).view;
}
在RecyclerView代理adapter相应的处理
@Override
public void onBindViewHolder(ViewHolder holder, int pos) {
int numHeaders = getHeadersCount();
// Header
if (pos < numHeaders) {
return;
}
// Adapter
final int adjPosition = pos - numHeaders;
int adapterCount = 0;
if (mAdapter != null) {
adapterCount = mAdapter.getItemCount();
if (adjPosition < adapterCount) {
mAdapter.onBindViewHolder(holder, adjPosition);
return;
}
}
// Footer (off-limits positions will throw an IndexOutOfBoundsException)
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
// Header
if (viewType == RecyclerView.INVALID_TYPE) {
return new HeaderViewHolder(mHeaderViewInfos.get(0));
} else if (viewType == RecyclerView.INVALID_TYPE - 1) {// Footer
return new HeaderViewHolder(mFooterViewInfos.get(0));
}
// Content
return mAdapter.onCreateViewHolder(parent, viewType);
}
总结:这只是一个简单的例子如果你懂ListView添加头部和底部的机制,那在RecyclerView中做到同样的功能只是分分钟的事情,只是要注意两者可能调用的方法不同,还有本文只是记录,并非指导开发,如有不详尽之处,勿喷。。。