关于XRecyclerView的解析...

XRecyclerView是对RecyclerView的封装,主要完成了下拉刷新、上拉加载更多、添加RecyclerView头部、显示空数据页面的功能,项目地址是Github---XRecyclerView。基本的使用,文档里面有,就不多说了,这里主要记录的是它怎么实现的。

XRecyclerView的类图

关于XRecyclerView的解析..._第1张图片
XRecyclerView的类图

1、关于WrapAdapter

1、创建ViewHolder(onCreateViewHolder())
为了显示不同类型的Item(HeaderViews、RefreshHeader、FootView),对传入的adapter做了封装:如果itemType是TYPE_REFRESH_HEADER、TYPE_FOOTER、HeaderType,创建SimpleViewHolder类型的ViewHolder进行展示,否则调用adapter.onCreateViewHolder()方法,交给子类创建。

2、绑定数据(onBindViewHolder())
需要排除HeaderViews、RefreshHeader、FootView的情况,调整position,调用adapter.onBindViewHolder()方法,让子类绑定。

3、计算itemType、itemCount等等

大概如下

   private WrapAdapter mWrapAdapter;

    @Override
    public void setAdapter(Adapter adapter) {
        //对传入的adapter做封装
        mWrapAdapter = new WrapAdapter(adapter);
        super.setAdapter(mWrapAdapter);
        adapter.registerAdapterDataObserver(mDataObserver);
        mDataObserver.onChanged();
    }

    private class WrapAdapter extends RecyclerView.Adapter {
        private RecyclerView.Adapter adapter;
        public WrapAdapter(RecyclerView.Adapter adapter) {
            this.adapter = adapter;
        }
        ...
        @Override
        public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            if (viewType == TYPE_REFRESH_HEADER) {
                return new SimpleViewHolder(mRefreshHeader);
            } else if (isHeaderType(viewType)) {
                //根据viewtype从对应的ArrayList中取出view来展示
                return new SimpleViewHolder(getHeaderViewByType(viewType));
            } else if (viewType == TYPE_FOOTER) {
                return new SimpleViewHolder(mFootView);
            }
            return adapter.onCreateViewHolder(parent, viewType);
        }

        @Override
        public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
            if (isHeader(position) || isRefreshHeader(position)) {
                return;
            }
            int adjPosition = position - (getHeadersCount() + 1);
            int adapterCount;
            if (adapter != null) {
                adapterCount = adapter.getItemCount();
                if (adjPosition < adapterCount) {
                    adapter.onBindViewHolder(holder, adjPosition);
                }
            }
        }

        @Override
        public int getItemCount() {
            if(loadingMoreEnabled) {
                if (adapter != null) {
                    return getHeadersCount() + adapter.getItemCount() + 2;
                } else {
                    return getHeadersCount() + 2;
                }
            }else {
                if (adapter != null) {
                    return getHeadersCount() + adapter.getItemCount() + 1;
                } else {
                    return getHeadersCount() + 1;
                }
            }
        }

        @Override
        public int getItemViewType(int position) {
            int adjPosition = position - (getHeadersCount() + 1);
            if (isRefreshHeader(position)) {
                return TYPE_REFRESH_HEADER;
            }
            if (isHeader(position)) {
                position = position - 1;
                return sHeaderTypes.get(position);
            }
            if (isFooter(position)) {
                return TYPE_FOOTER;
            }
            int adapterCount;
            if (adapter != null) {
                adapterCount = adapter.getItemCount();
                if (adjPosition < adapterCount) {
                    int type =  adapter.getItemViewType(adjPosition);
                    if(isReservedItemViewType(type)) {
                        throw new IllegalStateException("XRecyclerView require itemViewType in adapter should be less than 10000 " );
                    }
                    return type;
                }
            }
            return 0;
        }

        @Override
        public long getItemId(int position) {
            if (adapter != null && position >= getHeadersCount() + 1) {
                int adjPosition = position - (getHeadersCount() + 1);
                if (adjPosition < adapter.getItemCount()) {
                    return adapter.getItemId(adjPosition);
                }
            }
            return -1;
        }

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


2、添加HeaderViews

XRecyclerView 对外提供addHeaderView()方法添加header,其中使用了两个ArrayList存储不同的view和viewType。此时,通知mWrapAdapter,刷新界面。

    //HEADER_INIT_INDEX是保留值(ReservedItemViewType),如果用户的adapter与它们重复将会强制抛出异常。
    private static final int HEADER_INIT_INDEX = 10002;
    private ArrayList mHeaderViews = new ArrayList<>();
    //每个header必须有不同的type,不然滚动的时候顺序会变化
    private static List sHeaderTypes = new ArrayList<>();

    public void addHeaderView(View view) {
        sHeaderTypes.add(HEADER_INIT_INDEX + mHeaderViews.size());
        mHeaderViews.add(view);
        if (mWrapAdapter != null) {
            //刷新界面
            mWrapAdapter.notifyDataSetChanged();
        }
    }

3、空白数据处理

主要通过AdapterDataObserver 监听数据变化,并以此来更换布局(控制EmptyView、XRecyclerView的显示和隐藏),EmptyView是外部传进来的View。

   
    public void setEmptyView(View emptyView) {
        this.mEmptyView = emptyView;
        mDataObserver.onChanged();
    }

    private class DataObserver extends RecyclerView.AdapterDataObserver {
        @Override
        public void onChanged() {
            if (mWrapAdapter != null) {
                mWrapAdapter.notifyDataSetChanged();
            }
            if (mWrapAdapter != null && mEmptyView != null) {
                int emptyCount = 1 + mWrapAdapter.getHeadersCount();
                if (loadingMoreEnabled) {
                    emptyCount++;
                }
                if (mWrapAdapter.getItemCount() == emptyCount) {
                    mEmptyView.setVisibility(View.VISIBLE);
                    XRecyclerView.this.setVisibility(View.GONE);
                } else {

                    mEmptyView.setVisibility(View.GONE);
                    XRecyclerView.this.setVisibility(View.VISIBLE);
                }
            }
        }
        ...
    }

4、下拉刷新

下拉刷新分为两部分:手指滑动,refreshHeader慢慢显示出来(而且显示的大小跟滑动距离有关);释放后刷新界面、再慢慢隐藏。需要重写onTouchEvent,主要代码如下

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        if (mLastY == -1) {
            mLastY = ev.getRawY();
        }
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mLastY = ev.getRawY();
                break;
            case MotionEvent.ACTION_MOVE:
                final float deltaY = ev.getRawY() - mLastY;
                mLastY = ev.getRawY();
                if (isOnTop() && pullRefreshEnabled) {
                    //手指滑动距离的1/3,作为RefreshHeader显示的高度
                    mRefreshHeader.onMove(deltaY / DRAG_RATE);
                    if (mRefreshHeader.getVisibleHeight() > 0 && mRefreshHeader.getState() < IRefreshHeader.STATE_REFRESHING) {
                        return false;
                    }
                }
                break;
            default:
                mLastY = -1; // reset
                if (isOnTop() && pullRefreshEnabled) {
                    //在releaseAction()中处理了手指释放后,RefreshHeader刷新和慢慢向上隐藏的动作
                    if (mRefreshHeader.releaseAction()) {
                        if (mLoadingListener != null) {
                            mLoadingListener.onRefresh();
                        }
                    }
                }
                break;
        }
        return super.onTouchEvent(ev);
    }

    private boolean isOnTop() {
        if (mRefreshHeader.getParent() != null) {
            return true;
        } else {
            return false;
        }
    }

    //RefreshHeader慢慢向上隐藏
    public void refreshComplete() {
        mRefreshHeader.refreshComplete();
    }
   

其中,判断是否在顶部,使用的是mRefreshHeader.getParent(),因为ViewHolder是被复用的,一屏里最多有N+2个ViewHolder,如果recycleVIew没有在顶部,它的ViewHolder可能被其他的item复用了,所以mRefreshHeader.getParent()==null

关于XRecyclerView的解析..._第2张图片
下拉刷新

5、上拉加载更多

参考:拆解轮子之XRecyclerView


不喜勿喷

你可能感兴趣的:(关于XRecyclerView的解析...)