前言:相信很多人都知道,现在的日常开发中,已经逐渐由RecyclerView代替ListView、GridView,但相对于后者来说,RecyclerView存在着一些缺点,比如这篇文章要讲的,RecyclerView没有添加头部布局和底部布局的方法。
想到这里,我就想着那listview里面是怎么实现的呢?是不是可以去模仿Listview也写一个自己的RecyclerView,话不多说,直接开始
ListView源码分析:
//添加存放头部View和底部view的集合
private ArrayList<FixedViewInfo> mHeaderViewInfos = Lists.newArrayList();
private ArrayList<FixedViewInfo> mFooterViewInfos = Lists.newArrayList();
//添加头部
public void addHeaderView(View v, Object data, boolean isSelectable) {
//保存头部信息
final FixedViewInfo info = new FixedViewInfo();
info.view = v;
info.data = data;
info.isSelectable = isSelectable;
//添加信息到头部集合
mHeaderViewInfos.add(info);
mAreAllItemsSelectable &= isSelectable;
//如果mAdapter不为空,这个if的作用个人理解应该是在setAdapter后,用户假如再次添加头部布局,
会将原先已经经历过一次包装的HeaderViewListAdapter再一次包装
if (mAdapter != null) {
if (!(mAdapter instanceof HeaderViewListAdapter)) {
//如果此adapter没有被包装过,包装成具有HeaderView的adapter
mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, mAdapter);
}
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;
//如果mAdapter不为空,这个if的作用个人理解应该是在setAdapter后,用户假如再次添加底部布局,
会将原先已经经历过一次包装的HeaderViewListAdapter再一次包装
if (mAdapter != null) {
if (!(mAdapter instanceof HeaderViewListAdapter)) {
//如果此adapter没有被包装过,包装成具有FooterView的adapter
mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, mAdapter);
}
if (mDataSetObserver != null) {
mDataSetObserver.onChanged();
}
}
}
@Override
public void setAdapter(ListAdapter adapter) {
if (mAdapter != null && mDataSetObserver != null) {
mAdapter.unregisterDataSetObserver(mDataSetObserver);
}
resetList();
mRecycler.clear();
//如果头部集合或者底部集合不为空,则将Activity编写的adapter带入到HeadViewListAdapter进行包装,否则还是用原来的adapter
if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0) {
mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, adapter);
} else {
mAdapter = adapter;
}
mOldSelectedPosition = INVALID_POSITION;
mOldSelectedRowId = INVALID_ROW_ID;
// AbsListView#setAdapter will update choice mode states.
super.setAdapter(adapter);
if (mAdapter != null) {
mAreAllItemsSelectable = mAdapter.areAllItemsEnabled();
mOldItemCount = mItemCount;
mItemCount = mAdapter.getCount();
checkFocus();
mDataSetObserver = new AdapterDataSetObserver();
mAdapter.registerDataSetObserver(mDataSetObserver);
mRecycler.setViewTypeCount(mAdapter.getViewTypeCount());
int position;
if (mStackFromBottom) {
position = lookForSelectablePosition(mItemCount - 1, false);
} else {
position = lookForSelectablePosition(0, true);
}
setSelectedPositionInt(position);
setNextSelectedPositionInt(position);
if (mItemCount == 0) {
// Nothing selected
checkSelectionChanged();
}
} else {
mAreAllItemsSelectable = true;
checkFocus();
// Nothing selected
checkSelectionChanged();
}
requestLayout();
}
HeaderViewListAdapter:
//得到主体item、头部item、底部item总和
public int getCount() {
if (mAdapter != null) {
return getFootersCount() + getHeadersCount() + mAdapter.getCount();
} else {
return getFootersCount() + getHeadersCount();
}
}
//根据不同条件返回主体、头部、底部View
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;
}
以上代码运用了强大的装饰者模式,装饰者模式实现的是从一个对象外部给对象添加功能,
相当于改变了对象的外观,装饰过的对象,从外部系统来看已经不再是原来的对象,而是经过一系列装饰器装饰过的对象。
这里就是将自己的写的Adapter转换成了内部的HeadViewListAdapter。
这里我们知道了listview如何实现添加头部和底部布局的现在我们就来模仿listview做一个添加头部和底部布局的Recyclerview。
WrapRecyclerView.java:
public class WrapRecyclerView extends RecyclerView{
private ArrayList<View> mHeaderViewInfos = new ArrayList<View>();
private ArrayList<View> mFooterViewInfos = new ArrayList<View>();
private Adapter mAdapter;
public WrapRecyclerView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public void addHeaderView(View v) {
mHeaderViewInfos.add(v);
// Wrap the adapter if it wasn't already wrapped.
if (mAdapter != null) {
if (!(mAdapter instanceof HeaderViewRecyclerAdapter)) {
mAdapter = new HeaderViewRecyclerAdapter(mHeaderViewInfos, mFooterViewInfos, mAdapter);
}
}
}
public void addFooterView(View v) {
mFooterViewInfos.add(v);
// Wrap the adapter if it wasn't already wrapped.
if (mAdapter != null) {
if (!(mAdapter instanceof HeaderViewRecyclerAdapter)) {
mAdapter = new HeaderViewRecyclerAdapter(mHeaderViewInfos, mFooterViewInfos, mAdapter);
}
}
}
@Override
public void setAdapter(Adapter adapter) {
if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0) {
mAdapter = new HeaderViewRecyclerAdapter(mHeaderViewInfos, mFooterViewInfos, adapter);
} else {
mAdapter = adapter;
}
super.setAdapter(mAdapter);
}
}
HeaderViewRecyclerAdapter.java:
public class HeaderViewRecyclerAdapter extends RecyclerView.Adapter {
private RecyclerView.Adapter mAdapter;
ArrayList<View> mHeaderViewInfos;
ArrayList<View> mFooterViewInfos;
public HeaderViewRecyclerAdapter(ArrayList<View> headerViewInfos, ArrayList<View> footerViewInfos, RecyclerView.Adapter adapter) {
mAdapter = adapter;
if (headerViewInfos == null) {
mHeaderViewInfos = new ArrayList<View>();
} else {
mHeaderViewInfos = headerViewInfos;
}
if (footerViewInfos == null) {
mFooterViewInfos = new ArrayList<View>();
} else {
mFooterViewInfos = footerViewInfos;
}
}
//判读当前条目是什么类型的--决定渲染什么视图
@Override
public int getItemViewType(int position) {
int numHeaders = getHeadersCount();
if (position < numHeaders) { //是头部
return RecyclerView.INVALID_TYPE;
}
//正常条目部分
final int adjPosition = position - numHeaders;
int adapterCount = 0;
if (mAdapter != null) {
adapterCount = mAdapter.getItemCount();
if (adjPosition < adapterCount) {
return mAdapter.getItemViewType(adjPosition);
}
}
//footer部分
return RecyclerView.INVALID_TYPE - 1;
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
//header
if(viewType == RecyclerView.INVALID_TYPE){//头部
return new HeadViewHolder(mHeaderViewInfos.get(0));
}else if(viewType == RecyclerView.INVALID_TYPE-1){//尾部
return new HeadViewHolder(mFooterViewInfos.get(0));
}
return mAdapter.onCreateViewHolder(parent,viewType);
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
//也要划分三个区域
int numHeaders = getHeadersCount();
if (position < numHeaders) { //是头部
return;
}
//adapter body
final int adjPosition = position - numHeaders;
int adapterCount = 0;
if (mAdapter != null) {
adapterCount = mAdapter.getItemCount();
if (adjPosition < adapterCount) {
mAdapter.onBindViewHolder(holder,adjPosition);
return ;
}
}
//footer部分
}
@Override
public int getItemCount() {
if (mAdapter != null) {
return getFootersCount() + getHeadersCount() + mAdapter.getItemCount();
} else {
return getFootersCount() + getHeadersCount();
}
}
public int getHeadersCount() {
return mHeaderViewInfos.size();
}
public int getFootersCount() {
return mFooterViewInfos.size();
}
private static class HeadViewHolder extends RecyclerView.ViewHolder{
public HeadViewHolder(View itemView) {
super(itemView);
}
}
}
MyAdapter.java:
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
private List<String> list;
public MyAdapter(List<String> list) {
this.list = list;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
View view = layoutInflater.inflate(R.layout.listitem, parent, false);
ViewHolder holder = new ViewHolder(view);
return holder;
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.tv.setText(list.get(position));
}
@Override
public int getItemCount() {
return list.size();
}
public class ViewHolder extends RecyclerView.ViewHolder{
public TextView tv;
public ViewHolder(View itemView) {
super(itemView);
tv = (TextView) itemView.findViewById(R.id.tv);
}
}
}
MainActivity.java:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
WrapRecyclerView recyclerView = (WrapRecyclerView) findViewById(R.id.recyclerview);
//View headerView = View.inflate(this,resource,root);
TextView headerView = new TextView(this);
//TextView tv = headerView.findViewById(id);
ActionBar.LayoutParams params = new ActionBar.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
headerView.setLayoutParams(params);
headerView.setText("top");
recyclerView.addHeaderView(headerView);
TextView footview = new TextView(this);
footview.setLayoutParams(params);
footview.setText("bottom");
recyclerView.addFooterView(footview);
List<String> list = new ArrayList<>();
for (int i = 0; i < 30; i++) {
list.add("item"+i);
}
MyAdapter adapter = new MyAdapter(list);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setAdapter(adapter);
}
}
这里相关的布局文件也很简单,这里就不贴代码了。
总结完毕。
不喜勿喷 谢谢!