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

实现带header和footer功能的RecyclerView——完善篇

2017-08-07 16:48 507 查看
在上一篇文章中我们实现了实现带header和footer功能的RecyclerView,见
实现带header和footer功能的RecyclerView

但是由于加入了header,item的position有了变化,导致了RecyclerView中的一些与position有关方法或使用出现问题。本章着重解决一些常用的方法和使用,至于其他的解决方法类似。

首先,重写几个比较常用的方法,如下:

@Override
public int getChildAdapterPosition(View child) {
return super.getChildAdapterPosition(child) - mWrapAdapter.getHeaderCount();
}

@Override
public void swapAdapter(Adapter adapter, boolean removeAndRecycleExistingViews) {
mWrapAdapter.setAdapter(adapter);
super.swapAdapter(mWrapAdapter, removeAndRecycleExistingViews);
}

@Override
public ViewHolder findViewHolderForAdapterPosition(int position) {
return super.findViewHolderForAdapterPosition(position + mWrapAdapter.getHeaderCount());
}


总之涉及到item的position的方法和使用都要格外注意,在需要的时候对position进行相应处理。

比如getChildAdapterPosition,我们想知道item的position。但是由于RecyclerView中实际上使用的是WrapAdapter,所以获取的position是包括header的,所以要减去header的数量。

同理,在findViewHolderForAdapterPostion中,我们想通过外部adapter中item的postion获取该item的ViewHolder。实际上我们是要在WrapAdapter中去取,这时考虑到header需要为这个position加上header的数量才能取到正确的ViewHolder。

上面都是比较简单的,复杂一点比如divider。

在列表中我们经常会用到divider,RecyclerView并不像ListView那样可以很简单的添加divider,需要用户自定义一个ItemDecoration。

当我们定义ItemDecoration时就需要注意与position相关的计算,因为一般情况下divider只是给正常的item来使用,header和footer不需要使用(在其布局中已经包含了)。

由于我们一般用比较简单divider就可以了,所以这里实现了一个很简单的默认divider,如果需要自定义参考即可,代码如下:

public void setTransparentDivider(final int sizePx){
addItemDecoration(new ItemDecoration() {
@Override
public void onDraw(Canvas c, RecyclerView parent, State state) {
super.onDraw(c, parent, state);
}

@Override
public void onDrawOver(Canvas c, RecyclerView parent, State state) {
super.onDrawOver(c, parent, state);
}

@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, State state) {
int position = ((LayoutParams) view.getLayoutParams()).getViewLayoutPosition();

if(mWrapAdapter.isHeader(position) || mWrapAdapter.isFooter(position)){
super.getItemOffsets(outRect, view, parent, state);
return;
}

int index = position - mWrapAdapter.getHeaderCount();
if(isEnd(parent, index)){
if(isVertical(parent)){
outRect.set(0, 0, 0, sizePx);
}
else{
outRect.set(0, 0, sizePx, 0);
}
}
else{
outRect.set(0, 0, sizePx, sizePx);
}
}

private boolean isVertical(RecyclerView parent){
LayoutManager layout = parent.getLayoutManager();
if(layout instanceof StaggeredGridLayoutManager){
return ((StaggeredGridLayoutManager) layout).getOrientation() == StaggeredGridLayoutManager.VERTICAL;
}
else if(layout instanceof LinearLayoutManager){
return ((LinearLayoutManager) layout).getOrientation() == LinearLayoutManager.VERTICAL;
}
return true;
}

private int getSpanCount(RecyclerView parent){
LayoutManager layout = parent.getLayoutManager();
if(layout instanceof GridLayoutManager){
return ((GridLayoutManager) layout).getSpanCount();
}
if(layout instanceof StaggeredGridLayoutManager){
return ((StaggeredGridLayoutManager) layout).getSpanCount();
}
return 1;
}

private boolean isEnd(RecyclerView parent, int index){
int spanCount = getSpanCount(parent);
return (index + 1) % spanCount == 0;
}
});
}


关于ItemDecoration的实现网上有太多的文章了,这里就不细说了。主要说说position相关需要注意的地方。
重点关注getItemOffsets这个方法,通过getViewLayoutPosistion获取的position是item在WrapAdapter中的position。

首先判断是否是header或footer,如果是不添加。

普通的item,由于需要判断是否是一行的最后一个(isEnd,在GridLayoutManager或StaggeredGridLayoutManager中),所以要排除掉header对item位置的影响,这里减去header的数量。

通过上面的处理,header和footer的功能基本完善了,如果遇到其他问题,可以参照上面两种情况进行处理。

这样关于WrapRecyclerView的功能就告一段落了,有关onClickListener的功能很简单,大家看一下源码就明白了。至于更多的功能,我们以后再慢慢补充。

本项目的github地址是https://github.com/chzphoenix/PullToRefreshRecyclerView

下一章我们会在WrapRecyclerView的基础上实现PullToRefresh,即下拉刷新和上拉加载,敬请期待!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐