1. 程式人生 > >裝飾模式應用 為RecyclerView.Adapter新增上拉載入更多

裝飾模式應用 為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);

總結一下

雖然很多大神寫過這類文章,但是隻有自己動手實踐過才能更好的理解。