BaseRecyclerViewAdapterHelper開源項目之BaseQuickAdapter源碼學習上拉加載的實現代碼(三)

version:2.8.5

更多分享請看:http://cherylgood.cn

我們在上一章中分析了實現預加載功能的代碼,相信自己,你也可以,每個人都是創造者。

本章我將分析BaseRecyclerViewAdapterHelper 中 實現加載更多功能的代碼。

首先我們先了解幾個有關加載更多功能的方法,

第一步:打開上拉加載的開關

 /**
     * Set the enabled state of load more.
     *
     * @param enable True if load more is enabled, false otherwise.
     */
    public void setEnableLoadMore(boolean enable) {
        int oldLoadMoreCount = getLoadMoreViewCount();
        mLoadMoreEnable = enable;
        int newLoadMoreCount = getLoadMoreViewCount();

        if (oldLoadMoreCount == 1) {
            if (newLoadMoreCount == 0) {
                notifyItemRemoved(getHeaderLayoutCount() + mData.size() + getFooterLayoutCount());
            }
        } else {
            if (newLoadMoreCount == 1) {
                mLoadMoreView.setLoadMoreStatus(LoadMoreView.STATUS_DEFAULT);
                notifyItemInserted(getHeaderLayoutCount() + mData.size() + getFooterLayoutCount());
            }
        }
    }

通過上面方法打開我們的上拉加載的開關。首先我們先看下以下兩個變量的意思。

1、oldLoadMoreCount 代表在改變這個開關時我們是否處於顯示上拉加載的view的狀態,1表示處於該狀態。

2、newLoadMoreCount 代表我們當前是否可以開啓上拉加載功能,同樣,1表示可以。

這段代碼很有意思

        if (oldLoadMoreCount == 1) {
            if (newLoadMoreCount == 0) {
                notifyItemRemoved(getHeaderLayoutCount() + mData.size() + getFooterLayoutCount());
            }

我們爲什麼要做插入這段代碼呢,他的作用其實是這樣的:加入當前處於顯示加載更多view的狀態,此時你想關閉該開關,那我們第一件事要做什麼呢,當然是移除加載更多view 了,這段代碼的作用就是這個。

反過來,我們現在要開啓上拉加載。走的是這段代碼

else {
            if (newLoadMoreCount == 1) {
                mLoadMoreView.setLoadMoreStatus(LoadMoreView.STATUS_DEFAULT);
                notifyItemInserted(getHeaderLayoutCount() + mData.size() + getFooterLayoutCount());
            }
        }


因爲們的的loadMoreView一直是處於最底部的一個view,所以我們通過調用

notifyItemInserted(getHeaderLayoutCount() + mData.size() + getFooterLayoutCount());
告訴recycerlView將loadViewMore顯示出來。

當我們同過上拉加載加載新的數據完成後,我們需要告訴BaseQuickAdapter你可以恢復正常狀態了,此時我們將用到以下方法:
//加載完成第一個if是防止我們錯誤的調用該方法。可以看到,方法內部幫我們調用了更新數據源的方法。而且是局部更新。
/**
     * Refresh complete
     */
    public void loadMoreComplete() {
        if (getLoadMoreViewCount() == 0) {
            return;
        }
        mLoading = false;
        mLoadMoreView.setLoadMoreStatus(LoadMoreView.STATUS_DEFAULT);
        notifyItemChanged(getHeaderLayoutCount() + mData.size() + getFooterLayoutCount());
    }

我們看到這麼一句恢復我們的loadMoreView爲默認值,我們可以跟進去看下一下

        mLoadMoreView.setLoadMoreStatus(LoadMoreView.STATUS_DEFAULT);

他內部是重置了loadMoreStatus這個字段

 public void setLoadMoreStatus(int loadMoreStatus) {
        this.mLoadMoreStatus = loadMoreStatus;
    }

而這個字段是在什麼時候用到呢,LoadMoreView的代碼很少,可以看到

 public void convert(BaseViewHolder holder) {
        switch (mLoadMoreStatus) {
            case STATUS_LOADING:
                visibleLoading(holder, true);
                visibleLoadFail(holder, false);
                visibleLoadEnd(holder, false);
                break;
            case STATUS_FAIL:
                visibleLoading(holder, false);
                visibleLoadFail(holder, true);
                visibleLoadEnd(holder, false);
                break;
            case STATUS_END:
                visibleLoading(holder, false);
                visibleLoadFail(holder, false);
                visibleLoadEnd(holder, true);
                break;
            case STATUS_DEFAULT:
                visibleLoading(holder, false);
                visibleLoadFail(holder, false);
                visibleLoadEnd(holder, false);
                break;
        }
    }

他是在一個convert方法中根據mLoadMoreStatus來改變loadMoreView的顯示和隱藏,convert方法大家應該很熟悉,參數holder其實就是我們的loadMoreView本身,那麼loadMoreView.convert在哪被調用呢。

其實是在我們綁定數據時,如果判斷當前viewholder時loadMore類型,就會調用。

 @Override
    public void onBindViewHolder(K holder, int positions) {
        Log.d(TAG,"#test onBindViewHolder");
        int viewType = holder.getItemViewType();

        switch (viewType) {
            case 0:
                convert(holder, mData.get(holder.getLayoutPosition() - getHeaderLayoutCount()));
                break;
            case LOADING_VIEW:
                mLoadMoreView.convert(holder);
                break;
            case HEADER_VIEW:
                break;
            case EMPTY_VIEW:
                break;
            case FOOTER_VIEW:
                break;
            default:
                convert(holder, mData.get(holder.getLayoutPosition() - getHeaderLayoutCount()));
                break;
        }
    }

很好理解,我們的loadMoreView是一直存在的。作爲我們recyclerView的最後一個item,當加載到最後一個item的時候,他就調用loadView的convert方法,方法內部根據我們當前是否應該顯示loadView來做相應的操作。這樣我們就理解了loadMore的隱藏和顯示的邏輯了。後面還有兩個方法也很好理解,請看。

加載失敗調用,可能你有需求在加載失敗後要顯示一個加載失敗的view提示用戶,而不是直接關閉loadMoreView。此時你可以調用該方法。

    /**
     * Refresh failed
     */
    public void loadMoreFail() {
        if (getLoadMoreViewCount() == 0) {
            return;
        }
        mLoading = false;
        mLoadMoreView.setLoadMoreStatus(LoadMoreView.STATUS_FAIL);
        notifyItemChanged(getHeaderLayoutCount() + mData.size() + getFooterLayoutCount());
    }

 

/**
     * Refresh end, no more data
     *
     * @param gone if true gone the load more view
     */
    public void loadMoreEnd(boolean gone) {
        if (getLoadMoreViewCount() == 0) {
            return;
        }
        mLoading = false;
        mNextLoadEnable = false;
        mLoadMoreView.setLoadMoreEndGone(gone);
        if (gone) {
            notifyItemRemoved(getHeaderLayoutCount() + mData.size() + getFooterLayoutCount());
        } else {
            mLoadMoreView.setLoadMoreStatus(LoadMoreView.STATUS_END);
            notifyItemChanged(getHeaderLayoutCount() + mData.size() + getFooterLayoutCount());
        }
    }

之後就到我們關心的回調部分了。首先我們需要設置我們的回調監聽器

public void setOnLoadMoreListener(RequestLoadMoreListener requestLoadMoreListener) {
        this.mRequestLoadMoreListener = requestLoadMoreListener;
        mNextLoadEnable = true;
        mLoadMoreEnable = true;
        mLoading = false;
    }

在設置監聽器的時候,代碼也幫我們做了一個字段的賦值操作。默認開啓上拉加載,mLoading是表示當前是否處於上拉加載中。

接下來你可能要問,那這個mrequestLoadMoreListener在什麼時候被調用呢,其實這個也設計的比較好,上一章我們分析了預加載功能,其實就在上次介紹的代碼中。

private void autoLoadMore(int position) {
        //只有開啓了上拉加載且loadMoreView沒有gone且data.size>0 時返回1
        if (getLoadMoreViewCount() == 0) {
            return;
        }
        if (position < getItemCount() - mAutoLoadMoreSize) {
            return;
        }
        if (mLoadMoreView.getLoadMoreStatus() != LoadMoreView.STATUS_DEFAULT) {
            return;
        }
        mLoadMoreView.setLoadMoreStatus(LoadMoreView.STATUS_LOADING);
        if (!mLoading) {
            mLoading = true;
            mRequestLoadMoreListener.onLoadMoreRequested();
        }
    }

如果你想關閉預加載,當時是mAutoLoadMoreSize =0 ,此時要調用最後一句代碼,條件就變成了

position<getItemCount() ==false,而其成立的條件是position==getItemCount 也就是加載到最後一個item時。

思路大概是這樣的:

在關閉預加載功能時:如果加載到最後一個item,首先會調用getItemViewType詢問即將加載的viewholder是什麼類型。我們前面說過了,loadMoreView是一直作爲最後一個viewHolder存在的。此時如果符合顯示loadMoreView條件,那麼就設置loadMoreView的狀態,調用我們的函數。在執行到onBindViewHolder生命週期方法時,會根據我們設置的值顯示或者隱藏loadMoreView視圖,也就是說,onLoadMoreRequested方法的回調在顯示loadMoreView之前就被調用了。時間是很短的,用戶基本察覺不出來。

本次分析就到這裏,接下來會繼續分析其餘的代碼。如果有需要想一起分析哪部份代碼,也可以直接留言,我會調整順序。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章