旧机宝开发笔记之: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就修改完毕了。

现在这个下拉刷新上划加载更多的控件就准备完毕了,将在下一篇介绍具体的使用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值