
效果圖:

參考文章:
Android 優(yōu)雅的為RecyclerView添加HeaderView和FooterView
該功能主要是對(duì)adapter使用了裝飾者模式,具體代碼看下面的分析:
- HeaderAndFooterActivity.java
public class HeaderAndFooterActivity extends AppCompatActivity {
@BindView(R.id.recyclerView)
RecyclerView mRecyclerView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_header_and_footer);
ButterKnife.bind(this);
setTitle("添加Header和Footer");
//創(chuàng)建處理正常數(shù)據(jù)的adapter
HeaderAndFotterAdapter adapter = new HeaderAndFotterAdapter(this);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
//創(chuàng)建負(fù)責(zé)處理Header和footer的adpapter
HeaderAndFooterWrapper headerAndFooterWrapper = new HeaderAndFooterWrapper(adapter);
TextView t1 = new TextView(this);
t1.setText("Header 1");
TextView t2 = new TextView(this);
t2.setText("Header 2");
TextView t3 = new TextView(this);
t3.setText("Header 3");
TextView t4 = new TextView(this);
t4.setText("Header 4");
headerAndFooterWrapper.addHeaderView(t1);
headerAndFooterWrapper.addHeaderView(t2);
headerAndFooterWrapper.addFooterView(t3);
headerAndFooterWrapper.addFooterView(t4);
mRecyclerView.setLayoutManager(linearLayoutManager);
//RecyclerView的Adapter被賦值為headerAndFooterWrapper,
// 而正常處理數(shù)據(jù)的adapter在headerAndFooterWrapper中被調(diào)用
mRecyclerView.setAdapter(headerAndFooterWrapper);
}
}
上面代碼很簡(jiǎn)單,主要就是初始化兩個(gè)adpater和創(chuàng)建頭布局和底布局。
- HeaderAndFooterWrapper.java
public class HeaderAndFooterWrapper extends RecyclerView.Adapter<RecyclerView.ViewHolder>{
public static final int BASE_ITEM_TYPE_HEADER = 100000;
public static final int BASE_ITEM_TYPE_FOOTER = 200000;
private SparseArrayCompat<View> mHeaderViews = new SparseArrayCompat<>();
private SparseArrayCompat<View> mFooterViews = new SparseArrayCompat<>();
private RecyclerView.Adapter mInnerAdapter;
public HeaderAndFooterWrapper(RecyclerView.Adapter innerAdapter) {
mInnerAdapter = innerAdapter;
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (mHeaderViews.get(viewType) != null){
return new MyViewHolder(mHeaderViews.get(viewType));
}else if (mFooterViews.get(viewType) != null){
return new MyViewHolder(mFooterViews.get(viewType));
}
return mInnerAdapter.onCreateViewHolder(parent,viewType);
}
@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 int getItemViewType(int position) {
if (isHeaderViewPos(position)){
return mHeaderViews.keyAt(position);
}else if (isFooterViewPos(position)){
return mFooterViews.keyAt(position - getHeadersCount() - getRealItemCount());
}
return mInnerAdapter.getItemViewType(position - getHeadersCount());
}
/**
* 獲取正常數(shù)據(jù)的size
* @return
*/
private int getRealItemCount(){
return mInnerAdapter.getItemCount();
}
/**
* 判斷是否是Header
* @param position
* @return
*/
private boolean isHeaderViewPos(int position){
return position < getHeadersCount();
}
/**
* 判斷是否是Footer
* @param position
* @return
*/
private boolean isFooterViewPos(int position){
return position >= getHeadersCount() + getRealItemCount();
}
public void addHeaderView(View view){
mHeaderViews.put(mHeaderViews.size() + BASE_ITEM_TYPE_HEADER,view);
}
public void addFooterView(View view){
mFooterViews.put(mFooterViews.size() + BASE_ITEM_TYPE_FOOTER,view);
}
private int getHeadersCount(){
return mHeaderViews.size();
}
public int getFootersCount(){
return mFooterViews.size();
}
class MyViewHolder extends RecyclerView.ViewHolder{
public MyViewHolder(View itemView) {
super(itemView);
}
}
}
上面我們使用了線性布局,如果我們使用了網(wǎng)格和瀑布流,就有可能出問題咯,比如頭布局不能占據(jù)一行的問題。

下面是關(guān)于適配網(wǎng)格和瀑布流布局的解決方案:
在HeaderAndFooterWrapper.java中重寫下面的方法:
/**
* 適配網(wǎng)格布局
* @param recyclerView
*/
@Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
mInnerAdapter.onAttachedToRecyclerView(recyclerView);
final RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
if (layoutManager instanceof GridLayoutManager){
final GridLayoutManager gridLayoutManager = (GridLayoutManager) layoutManager;
gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
@Override
public int getSpanSize(int position) {
return isHeaderViewPos(position) || isFooterViewPos(position) ? ((GridLayoutManager) layoutManager).getSpanCount() : 1;
}
});
}
}
上面只解決了網(wǎng)格布局的,下面我們?cè)贖eaderAndFooterWrapper.java中可以重寫onViewAttachedToWindow方法解決瀑布流的問題。
@Override
public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) {
mInnerAdapter.onViewAttachedToWindow(holder);
int position = holder.getLayoutPosition();
if (isHeaderViewPos(position)||isFooterViewPos(position)){
ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams();
if (lp != null && lp instanceof StaggeredGridLayoutManager.LayoutParams){
StaggeredGridLayoutManager.LayoutParams p = (StaggeredGridLayoutManager.LayoutParams) lp;
p.setFullSpan(true);
}
}
}