您的位置:首页 > 移动开发

RecyclerView添加Header和Footer

2017-07-31 20:09 225 查看

本篇博客借鉴了 亓斌 大神的, RecyclerView添加Header的正确方式

自己想做一个类似微信的联系人界面,想到的解决方案就是在recyclerView添加header和footer。
做出来的效果如下:(界面有些丑,轻喷)



添加footer的时候也遇到了坑,最开始直接修改了getItemViewType方法,获得footer类型,和onCreateViewHolder方法里面加入创建footer的ViewHolder
@Override
public int getItemViewType(int position) {
if (mHeaderView == null) return TYPE_NORMAL;
if (position == 0) return TYPE_HEADER;
if (mFooterView == null) return TYPE_NORMAL;
if (position == getItemCount() - 1) return TYPE_FOOTER;
return TYPE_NORMAL;
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, final int viewType) {
if (mFooterView != null && viewType == TYPE_FOOTER) return new ViewHolder(mFooterView);
if (mHeaderView != null && viewType == TYPE_HEADER) return new ViewHolder(mHeaderView);
return onCreate(parent, viewType);
}





做了10个假数据后,拖动只可以看到8条数据。想想肯定是总数getItemCount方法的返回值有问题了
@Override
public int getItemCount() {
int itemCount = mDatas.size();
if (mHeaderView != null ) {
itemCount ++ ;
}
if (mFooterView != null) {
itemCount ++;
}
return itemCount;
}
修改后,继续重新运行,运行到recyclerView的第8个Item在拖动就报ClassCastException。
找了好久也没找到是哪里的问题,后来经过debug发现,在onBindViewHolder里面的第一行代码进行了对header类型的Item进行的return,想想自己也应该加上。
@Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
//防止出现ClassCastException
if (getItemViewType(position) == TYPE_HEADER) return;
if (getItemViewType(position) == TYPE_FOOTER) return;

int pos = getRealPosition(viewHolder);
T data = null;
//对数据进行判空,以免出现异常
if (mDatas != null && mDatas.size() > 0) {
data = mDatas.get(pos);
onBind(viewHolder, pos, data);
}
if (mListener != null) {
final T finalData = data;
final int finalPos = pos;
viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mListener.onItemClick(finalPos, finalData);
}
});
}
}
由于自己做的是联系人,在增加联系人后对数据要进行重新绑定,所以自己添加了onBindData方法,对recyclerView的数据重新赋值。

整体代码如下:

public abstract class BaseRecyclerAdapter<T> extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

public static final int TYPE_HEADER = 0;
public static final int TYPE_NORMAL = 1;
public static final int TYPE_FOOTER = 2;

public Context context;

public List<T> mDatas;

public BaseRecyclerAdapter(Context context, List<T> datas) {
this.context = context;
this.mDatas = datas;
}

private View mHeaderView;
public View mFooterView;

private OnItemClickListener mListener;

public void setOnItemClickListener(OnItemClickListener listener) {
mListener = listener;
}

/**
* 只可以添加一次headerView
* @param headerView
*/
public void setHeaderView(View headerView) {
mHeaderView = headerView;
notifyItemInserted(0);
}

public View getHeaderView() {
return mHeaderView;
}

/**
* 只可以添加一次footView
* @param footerView
*/
public void setFooterView(View footerView) {
mFooterView = footerView;
notifyItemInserted(getItemCount());
}

public View getFooterView() {
return mFooterView;
}

@Override
public int getItemViewType(int position) {
if (mHeaderView == null) return TYPE_NORMAL;
if (position == 0) return TYPE_HEADER;
if (mFooterView == null) return TYPE_NORMAL;
if (position == getItemCount() - 1) return TYPE_FOOTER;
return TYPE_NORMAL;
}

@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, final int viewType) {
if (mFooterView != null && viewType == TYPE_FOOTER) return new ViewHolder(mFooterView);
if (mHeaderView != null && viewType == TYPE_HEADER) return new ViewHolder(mHeaderView);
return onCreate(parent, viewType);
}

@Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
//防止出现ClassCastException
if (getItemViewType(position) == TYPE_HEADER) return;
if (getItemViewType(position) == TYPE_FOOTER) return;

int pos = getRealPosition(viewHolder);
T data = null;
//对数据进行判空,以免出现异常
if (mDatas != null && mDatas.size() > 0) {
data = mDatas.get(pos);
onBind(viewHolder, pos, data);
}
if (mListener != null) {
final T finalData = data;
final int finalPos = pos;
viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mListener.onItemClick(finalPos, finalData);
}
});
}
}

@Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);

RecyclerView.LayoutManager manager = recyclerView.getLayoutManager();
if (manager instanceof GridLayoutManager) {
final GridLayoutManager gridManager = ((GridLayoutManager) manager);
gridManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
@Override
public int getSpanSize(int position) {
return getItemViewType(position) == TYPE_HEADER
? gridManager.getSpanCount() : 1;
}
});
}
}

@Override
public void onViewAttachedToWindow(Rec
4000
yclerView.ViewHolder viewHolder) {
super.onViewAttachedToWindow(viewHolder);
ViewGroup.LayoutParams lp = viewHolder.itemView.getLayoutParams();
if (lp != null
&& lp instanceof StaggeredGridLayoutManager.LayoutParams) {
StaggeredGridLayoutManager.LayoutParams p = (StaggeredGridLayoutManager.LayoutParams) lp;
p.setFullSpan(viewHolder.getLayoutPosition() == 0);
}
}

/**
* 得到真正的位置position
* @param holder
* @return
*/
public int getRealPosition(RecyclerView.ViewHolder holder) {
int position = holder.getLayoutPosition();
return mHeaderView == null ? position : position - 1;
}
/**
* 得到recyclerView中的item总数
*/
@Override
public int getItemCount() {
int itemCount = mDatas.size();
if (mHeaderView != null ) {
itemCount ++ ;
}
if (mFooterView != null) {
itemCount ++;
}
return itemCount;
}
/**
* 得到recyclerView中的真正数据总数
*/
public int getRealItemCount(){
return mDatas.size();
}

public abstract RecyclerView.ViewHolder onCreate(ViewGroup parent, final int viewType);

public abstract void onBind(RecyclerView.ViewHolder viewHolder, int realPosition, T data);

public abstract void bindDatas(List<T> allNewFriend);

public class ViewHolder extends RecyclerView.ViewHolder {
public ViewHolder(View itemView) {
super(itemView);
}
}

public interface OnItemClickListener<T> {
void onItemClick(int position, T data);
}
}
使用方法:
public class AddressListPagerAdapter extends BaseRecyclerAdapter<Friend> {

public AddressListPagerAdapter(Context context, List<Friend> datas) {
super(context, datas);
}

@Override
public RecyclerView.ViewHolder onCreate(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.address_list_item, parent, false);
return new ViewHolder(itemView);
}

@Override
public void onBind(RecyclerView.ViewHolder viewHolder, int realPosition, Friend data) {
((ViewHolder) viewHolder).tv_friend_name.setText(mDatas.get(realPosition).getUsername());
RequestOptions requestOptions = new RequestOptions()
.placeholder(R.drawable.head)
.error(R.drawable.default_head);
Glide.with(context).load(mDatas.get(realPosition).getHeaderImage())
.apply(requestOptions)
.into(((ViewHolder) viewHolder).iv_head_portrait);
}

@Override
public void bindDatas(List<Friend> allNewFriend) {
mDatas = allNewFriend;
}

public class ViewHolder extends BaseRecyclerAdapter.ViewHolder {

private ImageView iv_head_portrait;
private TextView tv_friend_name;

public ViewHolder(View itemView) {
super(itemView);
iv_head_portrait = (ImageView) itemView.findViewById(R.id.iv_head_portrait);
tv_friend_name = (TextView) itemView.findViewById(R.id.tv_friend_name);
}
}
}

添加Header和Footer直接调用,setHeaderView和setFooterView方法既可以,header和footer点击事件没有在recyclerView里面进行处理,需要自己进行设置,个人感觉脱离了recyclerView的header和footer的点击事件处理起来更好一些,个人观点可能有点片面,不过应该具体情况具体分析吧。
唯一的一点遗憾就是在onBind里面进行绑定数据的时候需要对viewHolder进行强转。还有这样的方法只能添加一个header和一个footer,如果想多添加,可以将对应的view添加到header和footer中。如果还是不能满足你的需求,可以借鉴鸿洋_大神的方法
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android RecyclerView app