安卓进阶

实现带header和footer功能的RecyclerView—

2017-08-07  本文已影响69人  chzphoenix

在上一篇文章中我们实现了实现带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,即下拉刷新和上拉加载,敬请期待!

上一篇 下一篇

猜你喜欢

热点阅读