关于这个问题,我建议大家看看鸿大神的一篇博客,连接为http://blog.csdn.net/lmj623565791/article/details/51854533
首先说一点,在实际项目中有时会遇到本来我们的列表是不带Header的,突然一下产品抛出个需求要增加Header,我们又不得不去实现。
纵观整个界面,我们会发现,不管是Header还是Footer,都只不过是整个另一种viewType的item罢了。按照一般的做法,我们会想到增加一个特殊的viewType,然后去修改Adapter中的代码。那么,问题来了,你能保证这个Adapter是否只会在这一个地方使用,修改过后不会影响其他使用过这个Adapter的位置不出问题?谁也不能保证这点。按照我的原则来说,没有十足的把握或者还不到非做不可的情况下,那么就绝不要去修改前辈已经写好的代码。于是,我们可以考虑使用装饰着模式去装饰我们原来的Adapter,然后在需要的地方使用我们新的Adapter即可。
先分析一下需求,无非就是以下几个功能:
- 可增加HeaderView
- 可增加FooterView
- 适配多种LayoutManager
我们希望有几个方法:
void addHeaderView(View view);
void addHeaderView(View view, OnClickListener listener);
void addFooterView(View view);
void addFooterView(View view, OnClickListener listener);
直接看增加的代码:
RecyclerViewHeaderFooterWrapper
package com.zou.zohar.recyclerviewdemo.ui.adapter;
import android.support.v4.util.SparseArrayCompat;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.view.ViewGroup;
/**
* desc:
* Created by Zohar on 2017/4/27.
*/
public class RecyclerViewHeaderFooterWrapper extends RecyclerView.Adapter {
//BASE_ITEM_TYPE_HEADER 和 BASE_ITEM_TYPE_FOOTER 没有什么特殊的含义,
//只是用作将HeaderView和FooterView存放在SparseArrayCompat<View>容器中时的key值,方便取用
//具体使用见 addHeaderView(View view) 和 getItemViewType(int position) 以及 onCreateViewHolder(ViewGroup parent, int viewType) 方法
private static final int BASE_ITEM_TYPE_HEADER = 100000;
private static final int BASE_ITEM_TYPE_FOOTER = 200000;
private SparseArrayCompat<View> mHeaderViews = new SparseArrayCompat<>();//HeaderView的集合
private SparseArrayCompat<View.OnClickListener> mHeaderViewClickListeners = new SparseArrayCompat<>();//HeaderView监听事件的集合
private SparseArrayCompat<View> mFootViews = new SparseArrayCompat<>();//FooterView的集合
private SparseArrayCompat<View.OnClickListener> mFootViewClickListeners = new SparseArrayCompat<>();//FooterView监听事件的集合
private RecyclerView.Adapter mAdapter;//控制内容item的Adapter
public RecyclerViewHeaderFooterWrapper(RecyclerView.Adapter adapter) {
mAdapter = adapter;
}
/**
* Returns true if the item is HeaderView
*
* @param position position of the item to be examined
* @return true if item is HeaderView
*/
private boolean isHeaderView(int position) {
return position < getHeadersCount();
}
/**
* Returns true if the item is FooterView
*
* @param position position of the item to be examined
* @return true if item is FooterView
*/
private boolean isFooterView(int position) {
return position >= getHeadersCount() + getRealItemCount();
}
/**
* add a headerView
*
* @param view headerView
*/
public void addHeaderView(View view) {
addHeaderView(view, null);
}
/**
* add a headerView with clickListener
*
* @param view headerView
* @param listener clickListener
*/
public void addHeaderView(View view, View.OnClickListener listener) {
if (listener != null) {
mHeaderViewClickListeners.put(mHeaderViews.size() + BASE_ITEM_TYPE_HEADER, listener);
}
mHeaderViews.put(mHeaderViews.size() + BASE_ITEM_TYPE_HEADER, view);
}
/**
* add a footerView
*
* @param view footerView
*/
public void addFootView(View view) {
addFootView(view, null);
}
/**
* add a footerView with clickListener
*
* @param view footerView
* @param listener clickListener
*/
public void addFootView(View view, View.OnClickListener listener) {
if (listener != null) {
mFootViewClickListeners.put(mFootViews.size() + BASE_ITEM_TYPE_FOOTER, listener);
}
mFootViews.put(mFootViews.size() + BASE_ITEM_TYPE_FOOTER, view);
}
/**
* get the count of headers
*
* @return headersCount
*/
public int getHeadersCount() {
return mHeaderViews.size();
}
/**
* get the count of footers
*
* @return footersCount
*/
public int getFootersCount() {
return mFootViews.size();
}
/**
* get the count of items without headers and footers
*
* @return real itemsCount
*/
private int getRealItemCount() {
return mAdapter.getItemCount();
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (mHeaderViews.get(viewType) != null) {
ViewHolder holder = new ViewHolder(mHeaderViews.get(viewType));
if (mHeaderViewClickListeners.get(viewType) != null) {
holder.itemView.setOnClickListener(mHeaderViewClickListeners.get(viewType));
}
return holder;
} else if (mFootViews.get(viewType) != null) {
RecyclerView.ViewHolder holder = new ViewHolder(mFootViews.get(viewType));
if (mFootViewClickListeners.get(viewType) != null) {
holder.itemView.setOnClickListener(mFootViewClickListeners.get(viewType));
}
return holder;
}
return mAdapter.onCreateViewHolder(parent, viewType);
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if (isHeaderView(position)) {
return;
}
if (isFooterView(position)) {
return;
}
mAdapter.onBindViewHolder(holder, position - getHeadersCount());
}
@Override
public int getItemCount() {
return getHeadersCount() + getFootersCount() + getRealItemCount();
}
@Override
public int getItemViewType(int position) {
if (isHeaderView(position)) {
return mHeaderViews.keyAt(position);
} else if (isFooterView(position)) {
return mFootViews.keyAt(position - getHeadersCount() - getRealItemCount());
}
return mAdapter.getItemViewType(position - getHeadersCount());
}
@Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
mAdapter.onAttachedToRecyclerView(recyclerView);
final RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
if (layoutManager instanceof GridLayoutManager) {
final GridLayoutManager gridLayoutManager = (GridLayoutManager) layoutManager;
final GridLayoutManager.SpanSizeLookup oldLookup = gridLayoutManager.getSpanSizeLookup();
gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
@Override
public int getSpanSize(int position) {
int viewType = getItemViewType(position);
if (mHeaderViews.get(viewType) != null) {
return ((GridLayoutManager) layoutManager).getSpanCount();
} else if (mFootViews.get(viewType) != null) {
return ((GridLayoutManager) layoutManager).getSpanCount();
}
if (oldLookup != null) {
return oldLookup.getSpanSize(position);
}
return 1;
}
});
gridLayoutManager.setSpanCount(gridLayoutManager.getSpanCount());
}
}
private class ViewHolder extends RecyclerView.ViewHolder {
ViewHolder(View itemView) {
super(itemView);
}
}
}
使用起来也是相当的简单
LinearLayoutManager layoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
recyclerView.setLayoutManager(layoutManager);
RecyclerSimpleAdapter simpleAdapter = new RecyclerSimpleAdapter(dataList);//原本的Adapter
recyclerViewHeaderFooterWrapper = new RecyclerViewHeaderFooterWrapper(simpleAdapter);
//增加一个可点击的HeaderView
TextView header1 = new TextView(this);
header1.setText("header 1");
recyclerViewHeaderFooterWrapper.addHeaderView(header1, new View.OnClickListener() {
@Override
public void onClick(View v) {
Snackbar.make(v, "header 1", Snackbar.LENGTH_SHORT).show();
}
});
//增加一个不可点击的HeaderView
TextView header2 = new TextView(this);
header2.setText("header 2");
recyclerViewHeaderFooterWrapper.addHeaderView(header2);
//增加一个可点击的FooterView
TextView footer1 = new TextView(this);
footer1.setText("footer 1");
recyclerViewHeaderFooterWrapper.addFootView(footer1, new View.OnClickListener() {
@Override
public void onClick(View v) {
Snackbar.make(v, "footer 1", Snackbar.LENGTH_SHORT).show();
}
});
//增加一个不可点击的FooterView
TextView footer2 = new TextView(this);
footer2.setText("footer 2");
recyclerViewHeaderFooterWrapper.addFootView(footer2);
recyclerView.setAdapter(recyclerViewHeaderFooterWrapper);
RecyclerSimpleAdapter
package com.zou.zohar.recyclerviewdemo.ui.adapter;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.zou.zohar.recyclerviewdemo.R;
import java.util.List;
/**
* desc:简单的RecyclerView适配器
* Created by Zohar on 2017/4/7.
*/
public class RecyclerSimpleAdapter extends RecyclerView.Adapter<RecyclerSimpleAdapter.ViewHolder> {
private List<String> dates = null;
public RecyclerSimpleAdapter(List<String> dates) {
this.dates = dates;
}
@Override
public RecyclerSimpleAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_list_layout, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(final RecyclerSimpleAdapter.ViewHolder holder, final int position) {
holder.textView.setText(dates.get(position));
}
@Override
public int getItemCount() {
return dates.size();
}
class ViewHolder extends RecyclerView.ViewHolder {
LinearLayout llMain;
TextView textView;
ViewHolder(View itemView) {
super(itemView);
llMain = (LinearLayout) itemView.findViewById(R.id.ll_main);
textView = (TextView) itemView.findViewById(R.id.text);
}
}
}