舊機寶的用戶反饋、設備列表、功能列表等等都有可能存在大量數據,需要進行分頁顯示,一個下拉刷新上劃加載更多的控件是非常有必要的。這個時候就想到了原生的下拉刷新控件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就修改完畢了。
現在這個下拉刷新上劃加載更多的控件就準備完畢了,將在下一篇介紹具體的使用。