由于这次代码内容比较多这里我自己说的内容就尽量少点减少看文章的疲劳。首先还是先看效果图
1.CommonViewHolder类代码
/**
* Created by Administrator on 2018/2/25.
* 共通viewHolder用来完成各种view的操作
* 下面的功能比较少需要的童鞋可以根据自身业务需求添加方法
*/
public class CommonViewHolder extends RecyclerView.ViewHolder {
public View itemView;
public CommonViewHolder(View itemView) {
super(itemView);
this.itemView = itemView;
}
public View getItemView() {
return itemView;
}
public void setItemView(View itemView) {
this.itemView = itemView;
}
public View getView(int id) {
return itemView.findViewById(id);
}
public CommonViewHolder setText(int id, CharSequence text) {
((TextView) getView(id)).setText(text);
return this;
}
}
2.共通的普通适配器CommonAdapter
/**
* Created by Administrator on 2018/2/25.
* 共通Adapter
*/
public abstract class CommonAdapter<T> extends RecyclerView.Adapter<CommonViewHolder> {
private List<T> dates;//数据
private LayoutInflater inflater;//布局inflater
private int viewId;//布局的id
private MultiTypeSupport<T> typeSupport;//多布局支持
private OnItemClickListener itemClickListener;//单条点击事件
public CommonAdapter(Context context, List<T> dates, int viewId) {
this.dates = dates;
this.viewId = viewId;
inflater = LayoutInflater.from(context);
}
public CommonAdapter(Context context, List<T> dates, MultiTypeSupport<T> typeSupport) {
this.dates = dates;
this.typeSupport = typeSupport;
inflater = LayoutInflater.from(context);
}
public void removeItem(int position) {
dates.remove(position);
notifyDataSetChanged();
}
@Override
public int getItemViewType(int position) {
//多布局支持添加
if (typeSupport != null) {
return typeSupport.getViewId(dates.get(position), position);
}
return super.getItemViewType(position);
}
@Override
public CommonViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
//多布局支持添加
if (typeSupport != null) {
viewId = viewType;
}
return new CommonViewHolder(inflater.inflate(viewId, null));
}
@Override
public void onBindViewHolder(CommonViewHolder holder, int position) {
bindTheViewHolder(holder, dates.get(position));
final int finalPosition = position;
if (itemClickListener != null) {
holder.getItemView().setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
itemClickListener.onItemClick(finalPosition);
}
});
}
}
public abstract void bindTheViewHolder(CommonViewHolder holder, T date);
@Override
public int getItemCount() {
return dates.size();
}
public void setOnItemClickListener(OnItemClickListener itemClickListener) {
this.itemClickListener = itemClickListener;
}
public interface OnItemClickListener {
public <T> void onItemClick(int position);
}
}
3.接下来就是我们的WrapRecyclerViewAdapter了
/**
* Created by Administrator on 2018/2/25.
* 包裹头部和底部的适配器
*/
public class WrapRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private static int BASE_ITEM_TYPE_HEADER = 10000000; // 基本的头部类型开始位置 用于viewType
private static int BASE_ITEM_TYPE_FOOTER = 20000000; // 基本的尾部类型开始位置 用于viewType
RecyclerView.Adapter mAdapter;
SparseArray<View> headerViews;
SparseArray<View> footerViews;
public WrapRecyclerViewAdapter(RecyclerView.Adapter mAdapter) {
this.mAdapter = mAdapter;
headerViews = new SparseArray<>();
footerViews = new SparseArray<>();
}
@Override
public int getItemViewType(int position) {
if (position < headerViews.size()) {//头部
return headerViews.keyAt(position);
}
if (position > headerViews.size() + mAdapter.getItemCount()) {//底部
return footerViews.keyAt(position - headerViews.size() - mAdapter.getItemCount());
}
return mAdapter.getItemViewType(position - headerViews.size());//中间列表
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (headerViews.indexOfKey(viewType) >= 0) {
return createHeaderFooterViewHolder(headerViews.get(viewType));
}
if (footerViews.indexOfKey(viewType) >= 0) {
return createHeaderFooterViewHolder(footerViews.get(viewType));
}
return mAdapter.onCreateViewHolder(parent, viewType);
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if (position < headerViews.size() || position > headerViews.size() + mAdapter.getItemCount()) {//头部或者底部
return;
}
mAdapter.onBindViewHolder(holder, position - headerViews.size());
}
@Override
public int getItemCount() {
return mAdapter.getItemCount() + headerViews.size() + footerViews.size();
}
private RecyclerView.ViewHolder createHeaderFooterViewHolder(View view) {
return new RecyclerView.ViewHolder(view) {
};
}
public void addHeaderView(View view) {
if (headerViews.indexOfValue(view) != -1) return;
headerViews.put(BASE_ITEM_TYPE_HEADER++, view);
notifyDataSetChanged();
}
public void addFooterView(View view) {
if (footerViews.indexOfValue(view) != -1) return;
footerViews.put(BASE_ITEM_TYPE_FOOTER++, view);
notifyDataSetChanged();
}
public void removeHeaderView(View view) {
int viewIndex = headerViews.indexOfValue(view);
if (viewIndex == -1) return;
headerViews.removeAt(viewIndex);
notifyDataSetChanged();
}
public void removeFooterView(View view) {
int viewIndex = footerViews.indexOfValue(view);
if (viewIndex == -1) return;
footerViews.removeAt(viewIndex);
notifyDataSetChanged();
}
/**
* 解决GridLayoutManager添加头部和底部不占用一行的问题
*/
public void adjustSpanSize(RecyclerView recycler) {
if (recycler.getLayoutManager() instanceof GridLayoutManager) {
final GridLayoutManager layoutManager = (GridLayoutManager) recycler.getLayoutManager();
layoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
@Override
public int getSpanSize(int position) {
boolean isHeaderOrFooter = position < headerViews.size() || position > headerViews.size() + mAdapter.getItemCount();
return isHeaderOrFooter ? layoutManager.getSpanCount() : 1;
}
});
}
}
}
这里的主要思路就是
1.添加 SparseArray包裹的headerViews 和 footerViews用来保存我们添加的headerview和footerView。2.然后在getItemViewType判断位置返回headerView的key 和 footerView的key
3.onCreateViewHolder中通过SparseArray的 indexOfKey方法判断这个viewtype是否为headerview或者footerView的key 返回itemView
4.onBindViewHolder中通过判断position的位置如果为我们的适配器的position则调用适配器的onBindViewHolder
5.在getItemCount()中返回mAdapter.getItemCount() + headerViews.size() + footerViews.size()
6.添加headerViews 和footerViews的add delete方法
4.接下来就是我们要改写recyclerView的处理了
/**
* Created by Administrator on 2018/2/26.
*
*/
public class WrapRecyclerView extends RecyclerView {
// 包裹了一层的头部底部Adapter
private WrapRecyclerViewAdapter mWrapRecyclerAdapter;
// 这个是列表数据的Adapter
private RecyclerView.Adapter mAdapter;
public WrapRecyclerView(Context context) {
this(context, null);
}
public WrapRecyclerView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public WrapRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
public void setAdapter(Adapter adapter) {
// 为了防止多次设置Adapter
if (mAdapter != null) {
mAdapter.unregisterAdapterDataObserver(mDataObserver);
mAdapter = null;
}
this.mAdapter = adapter;
if (adapter instanceof WrapRecyclerViewAdapter) {
mWrapRecyclerAdapter = (WrapRecyclerViewAdapter) adapter;
} else {
mWrapRecyclerAdapter = new WrapRecyclerViewAdapter(adapter);
}
super.setAdapter(mWrapRecyclerAdapter);
// 注册一个观察者
mAdapter.registerAdapterDataObserver(mDataObserver);
// 解决GridLayout添加头部和底部也要占据一行
mWrapRecyclerAdapter.adjustSpanSize(this);
}
// 添加头部
public void addHeaderView(View view) {
// 如果没有Adapter那么就不添加,也可以选择抛异常提示
// 让他必须先设置Adapter然后才能添加,这里是仿照ListView的处理方式
if (mWrapRecyclerAdapter != null) {
mWrapRecyclerAdapter.addHeaderView(view);
}
}
// 添加底部
public void addFooterView(View view) {
if (mWrapRecyclerAdapter != null) {
mWrapRecyclerAdapter.addFooterView(view);
}
}
// 移除头部
public void removeHeaderView(View view) {
if (mWrapRecyclerAdapter != null) {
mWrapRecyclerAdapter.removeHeaderView(view);
}
}
// 移除底部
public void removeFooterView(View view) {
if (mWrapRecyclerAdapter != null) {
mWrapRecyclerAdapter.removeFooterView(view);
}
}
// 观察者 列表Adapter更新 包裹的也需要更新不然列表的notifyDataSetChanged没效果
private AdapterDataObserver mDataObserver = new AdapterDataObserver() {
@Override
public void onChanged() {
if (mAdapter == null) return;
if (mWrapRecyclerAdapter != mAdapter)
mWrapRecyclerAdapter.notifyDataSetChanged();
}
@Override
public void onItemRangeRemoved(int positionStart, int itemCount) {
if (mAdapter == null) return;
if (mWrapRecyclerAdapter != mAdapter) mWrapRecyclerAdapter.notifyItemRemoved(positionStart);
}
@Override
public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
if (mAdapter == null) return;
if (mWrapRecyclerAdapter != mAdapter) mWrapRecyclerAdapter.notifyItemMoved(fromPosition, toPosition);
}
@Override
public void onItemRangeChanged(int positionStart, int itemCount) {
if (mAdapter == null) return;
if (mWrapRecyclerAdapter != mAdapter) mWrapRecyclerAdapter.notifyItemChanged(positionStart);
}
@Override
public void onItemRangeChanged(int positionStart, int itemCount, Object payload) {
if (mAdapter == null) return;
if (mWrapRecyclerAdapter != mAdapter) mWrapRecyclerAdapter.notifyItemChanged(positionStart,payload);
}
@Override
public void onItemRangeInserted(int positionStart, int itemCount) {
if (mAdapter == null) return;
if (mWrapRecyclerAdapter != mAdapter) mWrapRecyclerAdapter.notifyItemInserted(positionStart);
}
};
}
这里我们仿照listview添加包裹header和footer的设置到我们的自定义的RecyclerView中去重要的一点是我们要写一个AdapterDataObserver用来当我们的普通adapter中列表刷新后通知我们的mWrapRecyclerAdapter去刷新界面,否则我们的里面的adapter的列表刷新了但是WrapRecyclerAdapter列表没刷新那么我们的列表不会发生变化。
最后的最后我们就是调用过程了很简单代码如下
public class Main2Activity extends AppCompatActivity {
List<String> items;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
items = new ArrayList<>();
for (int i = 0; i < 50; i++) {
items.add("-----" + i + "-----");
}
final WrapRecyclerView rc_main = (WrapRecyclerView) findViewById(R.id.rc_main);
rc_main.setLayoutManager(new LinearLayoutManager(Main2Activity.this, LinearLayoutManager.VERTICAL, false));
final MyAdapter adapter = new MyAdapter(Main2Activity.this, items, R.layout.item_vg);
adapter.setOnItemClickListener(new CommonAdapter.OnItemClickListener() {
@Override
public <T> void onItemClick(int position) {
items.remove(position);
adapter.notifyDataSetChanged();
Toast.makeText(Main2Activity.this, "点击了" + position, Toast.LENGTH_SHORT).show();
}
});
rc_main.setAdapter(adapter);
rc_main.addHeaderView(LayoutInflater.from(Main2Activity.this).inflate(R.layout.header, rc_main, false));
}
class MyAdapter extends CommonAdapter<String> {
public MyAdapter(Context context, List<String> dates, MultiTypeSupport<String> typeSupport) {
super(context, dates, typeSupport);
}
@Override
public void bindTheViewHolder(CommonViewHolder holder, String date) {
holder.setText(R.id.tv_content, date);
}
MyAdapter(Context context, List<String> dates, int viewId) {
super(context, dates, viewId);
}
}
}
文章说的不是很详细大家有什么意见欢迎提问。