结合 MultiType 实现加载更多

作者: 夏洛克的喵 | 来源:发表于2017-03-31 15:53 被阅读432次

    MultiType 是一个分发管理类,帮助我们轻松实现复杂布局.建议大家阅读源码,作者的思路并不复杂但很巧妙.

    下面附上主要源码:

    public class LoadMoreDelegate {
    
        private Items mItems;
    
        private MultiTypeAdapter mMultiTypeAdapter;
        private OnLoadMoreListener mOnLoadMoreListener;
        private ScrollListener mScrollListener;
    
    
        public LoadMoreDelegate(MultiTypeAdapter multiTypeAdapter, Items items, OnLoadMoreListener onLoadMoreListener) {
            mMultiTypeAdapter = multiTypeAdapter;
            mItems = items;
            this.mOnLoadMoreListener = onLoadMoreListener;
        }
    
        public void attach(RecyclerView recyclerView) {
            LinearLayoutManager linearLayoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
            mScrollListener = new ScrollListener(mMultiTypeAdapter, mItems, linearLayoutManager, mOnLoadMoreListener);
            recyclerView.addOnScrollListener(mScrollListener);
        }
    
        public void loadMoreComplete() {
            mScrollListener.setLoading(false);
        }
    
        public void addData(Items items) {
            int originSize = mItems.size() - 1;
            mItems.remove(originSize);//删除"加载更多"
            mItems.addAll(items);//添加新数据
            //从最后的位置插入新数据
            mMultiTypeAdapter.notifyItemRangeInserted(originSize, items.size() - 1);
        }
    
        public interface OnLoadMoreListener {
            void onLoadMore();
        }
    
        private static class ScrollListener extends RecyclerView.OnScrollListener {
            private final int size = 2;
            private boolean mLoading = false;
            private Items mItems;
            private final LoadMore mLoadMore = new LoadMore();
    
            private LinearLayoutManager mLinearLayoutManager;
            private OnLoadMoreListener mOnLoadMoreListener;
            private MultiTypeAdapter mMultiTypeAdapter;
    
            ScrollListener(MultiTypeAdapter multiTypeAdapter, Items datas, LinearLayoutManager linearLayoutManager, OnLoadMoreListener onLoadMoreListener) {
                mItems = datas;
                mMultiTypeAdapter = multiTypeAdapter;
                this.mLinearLayoutManager = linearLayoutManager;
                this.mOnLoadMoreListener = onLoadMoreListener;
            }
    
            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                if (dy < 0) {//下滑忽略
                    return;
                }
                int totalNum = mLinearLayoutManager.getItemCount();
                int lastVisiblePosition = mLinearLayoutManager.findLastCompletelyVisibleItemPosition();
                if (!mLoading && lastVisiblePosition == totalNum - size) {//最后可见的view的位置为倒数第size个,触发加载更多
                    mLoading = true;
                    mItems.add(mLoadMore);
                    mMultiTypeAdapter.notifyItemInserted(mItems.size() - 1);
                    mOnLoadMoreListener.onLoadMore();
                }
            }
    
            void setLoading(boolean loading) {
                this.mLoading = loading;
            }
        }
    
    }
    

    这里提下有些加载更多只是简单的直接使用 notifyDataSetChanged() 方法,效率上我没有研究过,不敢说哪个效率更好,但至少 RecycleView 给我们提供的动画效果没有了,所以建议还是采用 notifyItemInserted().

    完整示例:multitypeloadmore

    public class PullUpTestActivity extends AppCompatActivity implements LoadMoreDelegate.OnLoadMoreListener {
    
        private Items mItems = new Items();
    
        private LoadMoreDelegate mLoadMoreDelegate;
        @Bind(R.id.show)
        RecyclerView mShow;
    
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_pull_up);
            ButterKnife.bind(this);
            for (int i = 0; i < 20; i++) {
                mItems.add("data***" + i);
            }
    
    
            MultiTypeAdapter multiTypeAdapter = new MultiTypeAdapter(mItems);
            multiTypeAdapter.register(String.class, new NormalViewProvider());
            multiTypeAdapter.register(LoadMore.class, new LoadMoreViewProvider());
            mShow.setLayoutManager(new LinearLayoutManager(this));
            mShow.setAdapter(multiTypeAdapter);
            mLoadMoreDelegate = new LoadMoreDelegate(multiTypeAdapter, mItems, this);
            mLoadMoreDelegate.attach(mShow);
        }
    
        @Override
        public void onLoadMore() {
            getMore();
        }
    
        private void getMore() {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(2000);
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                Items strings = new Items();
                                for (int i = 0; i < 20; i++) {
                                    strings.add("data***more" + i);
                                }
                                mLoadMoreDelegate.addData(strings);
                                mLoadMoreDelegate.loadMoreComplete();
                            }
                        });
    
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
    
    
                }
            }).start();
        }
    }
    

    还有一点提一下,这样的必须需要滑动界面才可以触发加载更多,如果第一屏数据不超过一屏,将没法触发加载更多.但这样我认为是合理的,如果第一页数据的请求就不满一屏,所以后面应该是在没有数据的.有些加载更多的实现是一到最后一个数据,就开始加载更多.但在第一页数据不满一屏的情况下,触发了加载很多,很违背直觉. BaseRecyclerViewAdapterHelper 就采用了这种实现,大家可以去看源码. 而且一般第一页的请求,我们一般会有自己的一个 loading 视图,这样不满一屏的情况下,还有一个加载更多的视图,这是不太合理的.

    以上 demo 仅供参考,大家可以进一步自己封装和实现.可以自己实现个 MultiTypeAdapter 并把代码整合到里面去,这样用起来可能会更方便点.

    效果图

    loadmore.gif

    相关文章

      网友评论

        本文标题:结合 MultiType 实现加载更多

        本文链接:https://www.haomeiwen.com/subject/thdvottx.html