舊機寶開發筆記之:SwipeRefreshLayout+RecyclerView實現的下拉刷新上劃加載更多控件

舊機寶的用戶反饋、設備列表、功能列表等等都有可能存在大量數據,需要進行分頁顯示,一個下拉刷新上劃加載更多的控件是非常有必要的。這個時候就想到了原生的下拉刷新控件SwipeRefreshLayout,原生的應該支持最好也最簡單純粹,對於上劃加載更多則通過RecyclerView的滑動堅挺來實現,之所以選用RecyclerView是因爲其支持非常廣泛的佈局方式,有取代一衆listview的趨勢。爲了方便服用,直接封裝爲一個新的控件。
在這裏插入圖片描述

第一步:一個通知程序何時刷新、加載更多數據的接口

通過將該接口傳給adapter來實現刷新、加載更多數據的回調操作,接口代碼如下

interface OnLoadDataListener {
    fun refresh()
    fun loadMore()
}

第二步:一個嵌套RecyclerView的SwipeRefreshLayout控件

新建一個類RefreshLayout,使其繼承自SwipeRefreshLayout,因而具備SwipeRefreshLayout的下拉刷新能力,通過setOnRefreshListener把刷新事件通過接口OnLoadDataListener回調出去:

setOnRefreshListener {
            if (onLoadDataListener != null) {
                isRefreshing = true
                onLoadDataListener.refresh()
            } else {
                isRefreshing = false
            }
        }

在其實例化的時候,爲其加載一個RecyclerView,藉此實現數據容器和上劃加載更多的功能。通過addOnScrollListener的方式把上劃加載更多的事件回調出去,當RecyclerView的最後一項被顯示出來的時候,執行加載更多回調:

recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
            override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
                super.onScrollStateChanged(recyclerView, newState)
                if (newState == RecyclerView.SCROLL_STATE_IDLE) {
                    var lastVisiablePosition = 0
                    val layoutManager = recyclerView.getLayoutManager()
                    if (layoutManager is LinearLayoutManager) {
                        lastVisiablePosition = layoutManager
                            .findLastVisibleItemPosition()
                    } else if (layoutManager is GridLayoutManager) {
                        lastVisiablePosition = layoutManager
                            .findLastVisibleItemPosition()
                    } else if (layoutManager is StaggeredGridLayoutManager) {
                        val into = IntArray(
                            layoutManager
                                .getSpanCount()
                        )
                        layoutManager.findLastVisibleItemPositions(into)
                        lastVisiablePosition = findMax(into)
                    }
                                  }
                    val adapter:Adapter= recyclerView.adapter as Adapter
                    if (lastVisiablePosition == adapter.myGetItemCount()) {
                        if (onLoadDataListener != null && !isRefreshing()) {
                            adapter.showLoading()
                            onLoadDataListener.loadMore()
                        }
                    }
                }
            }
        })

RecyclerView通過layoutmanager來指定數據的顯示方式(幾行幾列橫向豎向),大部分情況下用的是豎向列表佈局,因而可以爲recyclerView設置一個默認的LinearLayoutManager,不過也要提供方法setLayoutManager來提供個性化的能力,最後,要有一個setAdapter方法來設置數據適配器,就像RecyclerView一樣。

fun setLayoutManager(layoutManager: RecyclerView.LayoutManager) {
        recyclerView.layoutManager = layoutManager
    }

    fun setAdapter(adapter: Adapter) {
        mAdapter=adapter
        recyclerView.adapter=mAdapter
    }

第三步:自定義一個Adapter,在最底層增加一個“正在加載中”的條目

該條目將成爲新的最後一項數據,當該條目被顯示的時候,觸發上劃加載更多回調。
在原來數據基礎之上增加一個條目

override fun getItemCount(): Int {
        return myGetItemCount() + 1
    }

爲該條目設置單獨的viewtype來區分

override fun getItemViewType(position: Int): Int {
        return if (position == myGetItemCount()) {
            viewTypeLoading
        } else {
            myGetItemViewType(position)
        }
    }

當加載該條目的時候,進行特殊的“沒有更多數據”條目顯示

override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
        if (position == myGetItemCount()) {
            (holder as LoadViewHolder).tvLoading.text = "沒有更多數據"
            tvLoadingTip = holder.tvLoading
            holder.progressBarLoading.visibility = View.GONE
            progressBarLoading = holder.progressBarLoading
        } else {
            myOnBindViewHolder(holder, position, myGetItemViewType(position))
        }
    }

該條目中的控件會被保存,用於修改加載狀態爲“正在加載中”還是“沒有更多數據”

internal inner class LoadViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        var tvLoading:TextView=itemView.findViewById(R.id.tv_loading)
        var progressBarLoading: ProgressBar = itemView.findViewById(R.id.progressBar_loading)
    }

    fun showLoading() {
        tvLoadingTip!!.text = "正在加載..."
        progressBarLoading!!.visibility = View.VISIBLE
    }

    fun finishLoad() {
        if (tvLoadingTip != null) tvLoadingTip!!.text = "沒有更多數據"
        if (progressBarLoading != null) progressBarLoading!!.visibility = View.GONE
    }

另外實現一些必須實現的方法定爲abstract要求子類去實現

protected abstract fun myOnCreateViewHolder(
        viewGroup: ViewGroup,
        viewType: Int
    ): RecyclerView.ViewHolder

    protected abstract fun myOnBindViewHolder(
        viewHolder: RecyclerView.ViewHolder,
        position: Int,
        viewType: Int
    )

    abstract fun myGetItemCount(): Int

    protected abstract fun myGetItemViewType(position: Int): Int

到這adapter就修改完畢了。

現在這個下拉刷新上劃加載更多的控件就準備完畢了,將在下一篇介紹具體的使用。

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