首先,RecyclerView 功能雖然強大但是沒有像ListView的addHaderView()或者addFooterView之類的方法,但是我們實際開發中可能需要這麼去做,必須我們自己去實作,為了給RecyclerView添加header 或者footer 我們今天來分析ListView是如何實作此功能的。
一、我們直接來看ListView.addHeaderView()方法,重點就是我們的adapter.
public void addHeaderView(View v, Object data, boolean isSelectable) {
//可以看到ListView把我們的HeaderView封裝成了對象FixedViewInfo 存在了集合當中
//private ArrayList<FixedViewInfo> mHeaderViewInfos = Lists.newArrayList();
//private ArrayList<FixedViewInfo> mFooterViewInfos = Lists.newArrayList();
//說明可以添加多個headerView 和 footerView
//
final FixedViewInfo info = new FixedViewInfo();
info.view = v;
info.data = data;
info.isSelectable = isSelectable;
mHeaderViewInfos.add(info);
mAreAllItemsSelectable &= isSelectable;
// Wrap the adapter if it wasn't already wrapped.
if (mAdapter != null) {
// 如果設定的adapter不是HeaderViewListAdapter 就建立一個HeaderViewListAdapter 并把mAdapter傳進去
// 這裡就是說如果 添加有headerView或者footerView 就是用HeaderViewListAdapter來裝飾我們的adapter
// 裝飾模式
if (!(mAdapter instanceof HeaderViewListAdapter)) {
mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, mAdapter);
}
// In the case of re-adding a header view, or adding one later on,
// we need to notify the observer.
if (mDataSetObserver != null) {
mDataSetObserver.onChanged();
}
}
}
二、繼續來看ListView.setAdapter()方法
@Override
public void setAdapter(ListAdapter adapter) {
if (mAdapter != null && mDataSetObserver != null) {
mAdapter.unregisterDataSetObserver(mDataSetObserver);
}
resetList();
mRecycler.clear();
這裡和 addHeaderView方法一樣裝飾了我們的adapter
if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0) {
mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, adapter);
} else {
mAdapter = adapter;
}
........................
requestLayout();
}
三、上面我們看到了 HeaderViewListAdapter來裝飾我們自己的adapter 我們這裡就來看一下 HeaderViewListAdapter
public class HeaderViewListAdapter implements WrapperListAdapter, Filterable {
private final ListAdapter mAdapter;
再看WraperListAdapter:
public interface WrapperListAdapter extends ListAdapter {
/**
* Returns the adapter wrapped by this list adapter.
*
* @return The {@link android.widget.ListAdapter} wrapped by this adapter.
*/
public ListAdapter getWrappedAdapter();
}
可以看到 HeaderViewListAdapter 和我們自己的傳進來的Adapter 都實作了ListAdapter接口,
這和我們普通的adapter沒有什麼大的差別 都擁有常用的方法 比如:getView()、getItem()、getCount()、getItemId()等
繼續看getView()方法:
//重點看這裡:
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();
// 代理(做一個切面的程式設計):根據不同的position傳回不同的view
if (adjPosition < adapterCount) {
return mAdapter.getView(adjPosition, convertView, parent);
}
}
// Footer (off-limits positions will throw an IndexOutOfBoundsException)
return mFooterViewInfos.get(adjPosition - adapterCount).view;
}
看到這裡我想大家都明白了,getCount(),getItem()也是同樣如此:
public int getCount() {
if (mAdapter != null) {
return getFootersCount() + getHeadersCount() + mAdapter.getCount();
} else {
return getFootersCount() + getHeadersCount();
}
}
getItemId()方法:
public long getItemId(int position) {
int numHeaders = getHeadersCount();
if (mAdapter != null && position >= numHeaders) {
int adjPosition = position - numHeaders;
int adapterCount = mAdapter.getCount();
if (adjPosition < adapterCount) {
return mAdapter.getItemId(adjPosition);
}
}
return -1;
}
看到這裡我們了解了 ListView添加HeaderView 和 FooterView的實作原理,可以為RecyclerView添加簡單的HeaderView 或者FooterView了。每天學一點,加油!