装饰模式应用 为RecyclerView.Adapter添加上拉加载更多

这个包装类主要有两个关键点:

第一个是列表尾部添加一个条目,用于显示各种加载的状态,就是添加了一个特殊类型的holder。

第二个是监控列表滚动,滚动到我们添加的那个holder的时候,触发我们需要的操作,比如修改holder里的状态文字等。

注意问题

以前做过两一个实现方案,主要的区别在第二点,方案没有监控列表滚动,而是在添加的尾部的holder绑定操作的时候,进行回调加载更多方案,然后在会掉中更新列表,原来类似。

传送门


原理介绍

1.添加一个新的类型的itemview用于显示我们的加载状态

 @Override
    public int getItemViewType(int position) {
        if (position == getItemCount() - 1) {
            return R.layout.lib_base_list_item_loading;
        } else {
            return mAdapter.getItemViewType(position);
        }
    }

2.创建holder的时候需要做区分,绑定holder的时候去更新一下我们添加的holder上的文字状态。

 @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        if (viewType == R.layout.lib_base_list_item_loading) {
            View view = LayoutInflater.from(parent.getContext()).inflate(viewType, parent, false);
            return new LoadingHolder(view, onLoadOrRetryListener);
        } else {
            return mAdapter.onCreateViewHolder(parent, viewType);
        }
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        if (holder instanceof LoadingHolder) {
            ((LoadingHolder) holder).bindHolder(mLoadState);
        } else {
            mAdapter.onBindViewHolder(holder, position);
        }
    }

3.设置一个监听器,监听RecyclerView.OnScrollListener的滚动事件,在这里进行调用加载更多的方法回调。

@Override
        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
            if (nextPageId == 0) {
                return;
            }
            int itemCount = mLayoutManager.getItemCount();
            int lastVisibleItemPosition = mLayoutManager.findLastVisibleItemPosition();
            //最后显示的view是不是我们列表的最后一个数据
            if (lastVisibleItemPosition == itemCount - 1) {
                //这个时候的刷新状态
                int loadState = mAdapter.getLoadState();
                //这里限制哪几种状态不用调用onLoadMore(nextPageId); 方法                   
                if (!isLoading && hasMore==LoadMoreAdapterWrapper.STATE_LOADING && loadState != LoadMoreAdapterWrapper.STATE_LOAD_FAILED
                        && loadState != LoadMoreAdapterWrapper.STATE_LOAD) {
                    isLoading = true;
                    //通过hanlder调用方法,防止出现异常
                    new Handler().post(new Runnable() {
                        @Override
                        public void run() {
                            onLoadMore(nextPageId);
                        }
                    });
                }
            }
        }

4.更新状态的方法外部调用该方法来,改变最后一个view的状态。下面是我使用到的状态,可以根据自己的需求进行调成。

public void updatePageInfo(int nextPageId, int hasMore) {
            this.nextPageId = nextPageId;
            this.hasMore = hasMore;
            this.isLoading = false;
            switch (hasMore) {
                case STATE_LOAD:
                    mAdapter.setLoadState(LoadMoreAdapterWrapper.STATE_LOAD);
                    break;
                case STATE_LOADING:
                    mAdapter.setLoadState(LoadMoreAdapterWrapper.STATE_LOADING);
                    break;
                case STATE_LOAD_FAILED:
                    mAdapter.setLoadState(LoadMoreAdapterWrapper.STATE_LOAD_FAILED);
                    break;
                case STATE_LOAD_HIDE:
                    mAdapter.setLoadState(LoadMoreAdapterWrapper.STATE_LOAD_HIDE);
                    break;
                case STATE_LOAD_HAVE_NO_DATA:
                    mAdapter.setLoadState(LoadMoreAdapterWrapper.STATE_LOAD_HAVE_NO_DATA);

                    break;
            }

            mAdapter.notifyDataSetChanged();
        }
以上就是关键的实现点了。

补充一点,就是在布局书网格的布局时,需要对loading布局进行处理,否则显示会不正确,现象为loading布局只能显示在第一个单元格内

@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) {
                    // 如果当前是footer的位置,那么该item占据2个单元格,正常情况下占据1个单元格
                    return getItemViewType(position) == TYPE_FOOTER ? gridManager.getSpanCount() : 1;
                }
            });
        }
    }


使用步骤一:

你需要让你的adapter继承BaseRecyclerViewAdapter,主要是为了使用里面的一些操作列表的方法。

使用步骤二:注释的比较详细

//要包装的adapter
dateBaseAdapter = new DateBaseAdapter(this);
 dateBaseAdapter.appendData(objects);
//布局管理器
        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
        linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
//adapter包装类初始化,将自己的adapter 穿入
        LoadMoreAdapterWrapper stringWrapperAdapter = new LoadMoreAdapterWrapper<>(this, dateBaseAdapter);
//初始化我们自己的监听方法
        onLoadMoreListener = new LoadMoreAdapterWrapper.OnLoadMoreListener(linearLayoutManager, stringWrapperAdapter) {
            @Override
            public void onLoadMore(int nextPageId) {
                LogUtils.d("--------" + page);
                viewById.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        page++;
                        onLoadMoreListener.updatePageInfo(page, LoadMoreAdapterWrapper.STATE_LOAD_FAILED);

                        dateBaseAdapter.appendData(objects);
                    }
                }, 1000);
            }
        };

        stringWrapperAdapter.setOnLoadOrRetryListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                viewById.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        page++;
                        onLoadMoreListener.updatePageInfo(page, LoadMoreAdapterWrapper.STATE_LOAD);
                        dateBaseAdapter.appendData(objects);
                    }
                }, 1000);
            }
        });
//第一次更新状态
        onLoadMoreListener.updatePageInfo(page, LoadMoreAdapterWrapper.STATE_LOADING);
//将监听方法设置给recycler view
        viewById.addOnScrollListener(onLoadMoreListener);

        viewById.setLayoutManager(linearLayoutManager);
        viewById.addItemDecoration(new DividerItemDecoration(this, LinearLayoutManager.HORIZONTAL));
//将包装类设置给recycler view
        viewById.setAdapter(stringWrapperAdapter);
总结一下

虽然很多大神写过这类文章,但是只有自己动手实践过才能更好的理解。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值