recyclerview实现加载更多

这里并没有重写recyclerview,只是对adapter进行了封装。
封装的adapter

/**
 *
 * @fuction recycleview 加载更多用的adpter
 * @date 2018/9/15
 * @author zhou
 */
abstract class RVLoadMoreAdapter(
    protected var mContext: Context,
    private val recyclerView: RecyclerView,
    private val res_item_id: Int,
    var dataSet: MutableList
) : RecyclerView.Adapter() {

    val TAG = RVLoadMoreAdapter::class.java.simpleName
    var isLoading = false
    private var canLoadMore = false
    private var loadMoreComplete = true
    private var loadingMore: OnLoadingMore? = null

    protected var mOnItemClickListener: OnItemClickListener? = null
    private var lastPositions: IntArray? = null
    private var footViewholder: RViewHolder? = null
    private var headerView: View? = null

    fun findMax(lastPositions: IntArray): Int {
        var max = lastPositions[0]
        for (value in lastPositions) {
            if (value > max) {
                max = value
            }
        }
        return max
    }

    fun loadMore() {
        loadingMore?.also {
            loadMoreComplete = true
            Loading(true)
            it.onLoadMore()
        }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RViewHolder {
        val holder: RViewHolder
        if (viewType == TYPE_HEAD) {
            holder = RViewHolder.createViewHolder(mContext, headerView!!)
        } else if (viewType == TYPE_LOAD_MORE) {
            if (footViewholder == null) {
                footViewholder = RViewHolder.createViewHolder(mContext, parent, R.layout.loadmore_default_footer)
            }
            holder = footViewholder!!
            showNormal()
        } else {
            holder = RViewHolder.createViewHolder(mContext, parent, res_item_id)
        }
        onViewHolderCreated(holder, holder.convertView, viewType)
        setListener(parent, holder, viewType)
        return holder
    }

    open fun onViewHolderCreated(
        holder: RViewHolder,
        itemView: View,
        viewType: Int
    ) {
    }

    override fun onBindViewHolder(holder: RViewHolder, position: Int) {
        if (getItemViewType(position) == TYPE_LOAD_MORE) {
            return
        }
        if (getItemViewType(position) == TYPE_HEAD) {
            return
        }
        val p = if (headerView != null) position - 1 else position
        val t = dataSet[p]
        convert(holder, t, p)
    }

    protected abstract fun convert(holder: RViewHolder, t: T, position: Int)
    override fun getItemCount(): Int {
        var size = dataSet.size
        if (headerView != null) {
            size++
        }
        if (canLoadMore) {
            size++
        }
        return size
    }

    override fun getItemViewType(position: Int): Int {
        if (position == 0) {
            if (headerView != null) {
                return TYPE_HEAD
            }
        }
        if (canLoadMore) {
            if (position == itemCount - 1) {
                return TYPE_LOAD_MORE
            }
        }
        return TYPE_NORMAL
    }

    fun setLoadingMore(loadingMore: OnLoadingMore?) {
        this.loadingMore = loadingMore
    }

    fun Loading(loading: Boolean) {
        isLoading = loading
        showNormal()
    }

    fun setLoadMoreComplete(complete: Boolean) {
        canLoadMore = loadingMore != null
        loadMoreComplete = complete
    }

    private var custom_layout_empty: LinearLayout? = null
    fun showNormal() {
        canLoadMore = loadingMore != null
        if (!canLoadMore) {
            return
        }
        if (footViewholder == null) {
            return
        }
        if (loadMoreComplete) {
            footViewholder!!.setVisible(R.id.layout_empty_default, true)
            val loadmore_default_footer_tv = footViewholder!!.getView(R.id.loadmore_default_footer_tv)
            if (isLoading) {
                loadmore_default_footer_tv.text = "加载中"
                loadmore_default_footer_tv.setOnClickListener(null)
                footViewholder!!.setVisible(R.id.loadmore_default_footer_progressbar, true)
            } else {
                loadmore_default_footer_tv.text = "点击加载更多"
                loadmore_default_footer_tv.setOnClickListener { loadMore() }
                footViewholder!!.setVisible(R.id.loadmore_default_footer_progressbar, false)
            }
            custom_layout_empty?.visibility = View.GONE
        } else {
            if (dataSet.size > 0) {
                footViewholder!!.setVisible(R.id.layout_empty_default, true)
                footViewholder!!.setText(R.id.loadmore_default_footer_tv, "无更多数据")
                footViewholder!!.setVisible(R.id.loadmore_default_footer_progressbar, false)
                custom_layout_empty?.visibility = View.GONE
            } else {
                footViewholder!!.setVisible(R.id.layout_empty_default, false)
                if (custom_layout_empty == null) {
                    var stub_import = footViewholder!!.itemView.findViewById(R.id.stub_import)
                    if (stub_import != null) {
                        stub_import.inflate()
                        stub_import = null
                    }
                    custom_layout_empty = footViewholder!!.getView(R.id.custom_layout_empty)
                    if (!TextUtils.isEmpty(emptyText)) {
                        val tv_empty = custom_layout_empty!!.findViewById(R.id.tv_empty)
                        tv_empty.text = emptyText
                    }
                    val iv_empty = custom_layout_empty!!.findViewById(R.id.iv_empty)
                    iv_empty.setImageResource(emptyRes)
                }
                custom_layout_empty!!.visibility = View.VISIBLE
            }
        }
    }

    fun addData(t: T) {
        dataSet!!.add(t)
        notifyDataSetChanged()
    }

    interface OnLoadingMore {
        fun onLoadMore()
    }

    protected fun setListener(
        parent: ViewGroup?,
        viewHolder: RViewHolder,
        viewType: Int
    ) {
        viewHolder.convertView.setOnClickListener(View.OnClickListener { v ->
            mOnItemClickListener?.also {
                val position = viewHolder.adapterPosition
                if (TYPE_HEAD == getItemViewType(position)) {
                    return@OnClickListener
                }
                if (TYPE_LOAD_MORE == getItemViewType(position)) {
                    return@OnClickListener
                }
                val p = if (headerView != null) position - 1 else position
                it.onItemClick(v, viewHolder, p)
            }
        })
        viewHolder.convertView.setOnLongClickListener(OnLongClickListener { v ->
            mOnItemClickListener?.also {
                val position = viewHolder.adapterPosition
                if (TYPE_HEAD == getItemViewType(position)) {
                    return@OnLongClickListener false
                }
                if (TYPE_LOAD_MORE == getItemViewType(position)) {
                    return@OnLongClickListener false
                }
                val p = if (headerView != null) position - 1 else position
                return@OnLongClickListener it.onItemLongClick(v, viewHolder, p)
            }
            false
        })
    }

    interface OnItemClickListener {
        fun onItemClick(
            view: View,
            holder: ViewHolder,
            position: Int
        )

        fun onItemLongClick(
            view: View,
            holder: ViewHolder,
            position: Int
        ): Boolean
    }

    fun setOnItemClickListener(onItemClickListener: OnItemClickListener?) {
        mOnItemClickListener = onItemClickListener
    }

    fun addHeaderView(view: View?) {
        headerView = view
    }

    fun setCanLoadMore(canLoadMore: Boolean) {
        this.canLoadMore = canLoadMore
    }

    private var emptyText: String? = null
    private var emptyRes = R.drawable.icon_empty_default
    fun setEmptyContent(txt: String?, res: Int) {
        emptyText = txt
        emptyRes = res
    }

    fun setEmptyRes(emptyRes: Int) {
        this.emptyRes = emptyRes
    }

    fun setEmptyText(emptyText: String?) {
        this.emptyText = emptyText
    }

    companion object {
        const val TYPE_NORMAL = 100
        const val TYPE_HEAD = 101
        const val TYPE_LOAD_MORE = 102
    }

    init {
        //监听recylerview的滑动
        recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
            override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
                super.onScrolled(recyclerView, dx, dy)
                if (dy <= 0) {
                    return
                }
                if (loadMoreComplete && canLoadMore && !isLoading) {
                    var lastVisibleItem = 0
                    val layoutManager = recyclerView.layoutManager
                    if (layoutManager is LinearLayoutManager) {
                        lastVisibleItem = layoutManager.findLastVisibleItemPosition()
                    } else if (layoutManager is GridLayoutManager) {
                        lastVisibleItem = layoutManager.findLastVisibleItemPosition()
                    } else if (layoutManager is StaggeredGridLayoutManager) {
                        if (lastPositions == null) {
                            lastPositions = IntArray(layoutManager.spanCount)
                        }
                        layoutManager.findLastVisibleItemPositions(lastPositions)
                        lastVisibleItem = findMax(lastPositions!!)
                    } else {
                        throw RuntimeException(
                            "Unsupported LayoutManager used. Valid ones are LinearLayoutManager, GridLayoutManager and StaggeredGridLayoutManager"
                        )
                    }
                    if (lastVisibleItem + 1 == itemCount) {
                        loadMore()
                    }
                }
            }
        })
    }
}

该adapter分别可以适配线性列表,grid列表,瀑布流列表三种布局的加载更多。
使用方法:线性列表

 val layoutManager = LinearLayoutManager(this); //线性布局
        recyclerview.layoutManager = layoutManager
        homeAdapter = object: RVLoadMoreAdapter(this@AdapterMoreLoad1Activity,recyclerview,R.layout.item_rv_txt, mDatas){
            override fun convert(holder: RViewHolder, t: String, position: Int) {
                holder.setText(R.id.txt,mDatas[position])
            }

        }

        recyclerview.adapter = homeAdapter

        homeAdapter!!.setOnItemClickListener(object: RVLoadMoreAdapter.OnItemClickListener{
            override fun onItemClick(view: View, holder: RecyclerView.ViewHolder, position: Int) {
                
            }

            override fun onItemLongClick(
                view: View,
                holder: RecyclerView.ViewHolder,
                position: Int
            ): Boolean {
                return false
            }

        })
 homeAdapter!!.setLoadingMore(object: RVLoadMoreAdapter.OnLoadingMore{
            override fun onLoadMore() {
                downJson(mCurrentPage+1)
            }

        })

在downjson是可以是接口获取数据,获取完数据需要做一些操作,如下

 private fun downJson(page: Int) {

        Handler().postDelayed(Runnable {
            swipe_layout.isRefreshing = false
            if(page == 1){
                mDatas.clear()
                homeAdapter!!.setLoadMoreComplete(true)
            }
            mCurrentPage = page
            val datalist = ArrayList()

            if(page == 3){ //模拟滑动到最底部
                for (i in 1..7){
                    datalist.add("RecyclerView使用$i")
                }
            }else{
                for (i in 1..20){
                    datalist.add("RecyclerView使用$i")
                }
            }
            mDatas.addAll(datalist)
            if (datalist.size < 20) {
                homeAdapter!!.setLoadMoreComplete(false)
            }

            homeAdapter!!.notifyDataSetChanged()
            homeAdapter!!.Loading(false)
        },1000)

    }

具体操作大家可以自己分析,还是很容易理解。

这里特别注意:用grid列表的时候需要加入

layoutManager.spanSizeLookup = object: GridLayoutManager.SpanSizeLookup() {
            override fun getSpanSize(position: Int): Int {
                return if (homeAdapter!!.getItemViewType(position) == RVLoadMoreAdapter.TYPE_LOAD_MORE) {
                    2
                } else {
                    1
                }
            }

        }

这样加载更多的底部布局才能跨列显示。上面的2是因为我用的是2列的grid,如果是3列就是3,以此类推。

瀑布流的时候,需要重写onViewHolderCreated的方法,解决加载更多的跨列问题,如下

homeAdapter = object: RVLoadMoreAdapter(this@AdapterMoreLoad3Activity,recyclerview,R.layout.item_rv_txt, mDatas){

            override fun onViewHolderCreated(holder: RViewHolder, itemView: View, viewType: Int) {
                super.onViewHolderCreated(holder, itemView, viewType)
                if (viewType === TYPE_LOAD_MORE) {
                    val lp = holder.itemView.layoutParams
                    if (lp != null && lp is StaggeredGridLayoutManager.LayoutParams) {
                        lp.isFullSpan = true
                    }
                }
            }

            override fun convert(holder: RViewHolder, t: String, position: Int) {
                holder.setText(R.id.txt,mDatas[position])
            }

        }

这里并没有重写recyclerview,只是对adapter进行了封装。
封装的adapter

/**
 *
 * @fuction recycleview 加载更多用的adpter
 * @date 2018/9/15
 * @author zhou
 */
abstract class RVLoadMoreAdapter(
    protected var mContext: Context,
    private val recyclerView: RecyclerView,
    private val res_item_id: Int,
    var dataSet: MutableList
) : RecyclerView.Adapter() {

    val TAG = RVLoadMoreAdapter::class.java.simpleName
    var isLoading = false
    private var canLoadMore = false
    private var loadMoreComplete = true
    private var loadingMore: OnLoadingMore? = null

    protected var mOnItemClickListener: OnItemClickListener? = null
    private var lastPositions: IntArray? = null
    private var footViewholder: RViewHolder? = null
    private var headerView: View? = null

    fun findMax(lastPositions: IntArray): Int {
        var max = lastPositions[0]
        for (value in lastPositions) {
            if (value > max) {
                max = value
            }
        }
        return max
    }

    fun loadMore() {
        loadingMore?.also {
            loadMoreComplete = true
            Loading(true)
            it.onLoadMore()
        }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RViewHolder {
        val holder: RViewHolder
        if (viewType == TYPE_HEAD) {
            holder = RViewHolder.createViewHolder(mContext, headerView!!)
        } else if (viewType == TYPE_LOAD_MORE) {
            if (footViewholder == null) {
                footViewholder = RViewHolder.createViewHolder(mContext, parent, R.layout.loadmore_default_footer)
            }
            holder = footViewholder!!
            showNormal()
        } else {
            holder = RViewHolder.createViewHolder(mContext, parent, res_item_id)
        }
        onViewHolderCreated(holder, holder.convertView, viewType)
        setListener(parent, holder, viewType)
        return holder
    }

    open fun onViewHolderCreated(
        holder: RViewHolder,
        itemView: View,
        viewType: Int
    ) {
    }

    override fun onBindViewHolder(holder: RViewHolder, position: Int) {
        if (getItemViewType(position) == TYPE_LOAD_MORE) {
            return
        }
        if (getItemViewType(position) == TYPE_HEAD) {
            return
        }
        val p = if (headerView != null) position - 1 else position
        val t = dataSet[p]
        convert(holder, t, p)
    }

    protected abstract fun convert(holder: RViewHolder, t: T, position: Int)
    override fun getItemCount(): Int {
        var size = dataSet.size
        if (headerView != null) {
            size++
        }
        if (canLoadMore) {
            size++
        }
        return size
    }

    override fun getItemViewType(position: Int): Int {
        if (position == 0) {
            if (headerView != null) {
                return TYPE_HEAD
            }
        }
        if (canLoadMore) {
            if (position == itemCount - 1) {
                return TYPE_LOAD_MORE
            }
        }
        return TYPE_NORMAL
    }

    fun setLoadingMore(loadingMore: OnLoadingMore?) {
        this.loadingMore = loadingMore
    }

    fun Loading(loading: Boolean) {
        isLoading = loading
        showNormal()
    }

    fun setLoadMoreComplete(complete: Boolean) {
        canLoadMore = loadingMore != null
        loadMoreComplete = complete
    }

    private var custom_layout_empty: LinearLayout? = null
    fun showNormal() {
        canLoadMore = loadingMore != null
        if (!canLoadMore) {
            return
        }
        if (footViewholder == null) {
            return
        }
        if (loadMoreComplete) {
            footViewholder!!.setVisible(R.id.layout_empty_default, true)
            val loadmore_default_footer_tv = footViewholder!!.getView(R.id.loadmore_default_footer_tv)
            if (isLoading) {
                loadmore_default_footer_tv.text = "加载中"
                loadmore_default_footer_tv.setOnClickListener(null)
                footViewholder!!.setVisible(R.id.loadmore_default_footer_progressbar, true)
            } else {
                loadmore_default_footer_tv.text = "点击加载更多"
                loadmore_default_footer_tv.setOnClickListener { loadMore() }
                footViewholder!!.setVisible(R.id.loadmore_default_footer_progressbar, false)
            }
            custom_layout_empty?.visibility = View.GONE
        } else {
            if (dataSet.size > 0) {
                footViewholder!!.setVisible(R.id.layout_empty_default, true)
                footViewholder!!.setText(R.id.loadmore_default_footer_tv, "无更多数据")
                footViewholder!!.setVisible(R.id.loadmore_default_footer_progressbar, false)
                custom_layout_empty?.visibility = View.GONE
            } else {
                footViewholder!!.setVisible(R.id.layout_empty_default, false)
                if (custom_layout_empty == null) {
                    var stub_import = footViewholder!!.itemView.findViewById(R.id.stub_import)
                    if (stub_import != null) {
                        stub_import.inflate()
                        stub_import = null
                    }
                    custom_layout_empty = footViewholder!!.getView(R.id.custom_layout_empty)
                    if (!TextUtils.isEmpty(emptyText)) {
                        val tv_empty = custom_layout_empty!!.findViewById(R.id.tv_empty)
                        tv_empty.text = emptyText
                    }
                    val iv_empty = custom_layout_empty!!.findViewById(R.id.iv_empty)
                    iv_empty.setImageResource(emptyRes)
                }
                custom_layout_empty!!.visibility = View.VISIBLE
            }
        }
    }

    fun addData(t: T) {
        dataSet!!.add(t)
        notifyDataSetChanged()
    }

    interface OnLoadingMore {
        fun onLoadMore()
    }

    protected fun setListener(
        parent: ViewGroup?,
        viewHolder: RViewHolder,
        viewType: Int
    ) {
        viewHolder.convertView.setOnClickListener(View.OnClickListener { v ->
            mOnItemClickListener?.also {
                val position = viewHolder.adapterPosition
                if (TYPE_HEAD == getItemViewType(position)) {
                    return@OnClickListener
                }
                if (TYPE_LOAD_MORE == getItemViewType(position)) {
                    return@OnClickListener
                }
                val p = if (headerView != null) position - 1 else position
                it.onItemClick(v, viewHolder, p)
            }
        })
        viewHolder.convertView.setOnLongClickListener(OnLongClickListener { v ->
            mOnItemClickListener?.also {
                val position = viewHolder.adapterPosition
                if (TYPE_HEAD == getItemViewType(position)) {
                    return@OnLongClickListener false
                }
                if (TYPE_LOAD_MORE == getItemViewType(position)) {
                    return@OnLongClickListener false
                }
                val p = if (headerView != null) position - 1 else position
                return@OnLongClickListener it.onItemLongClick(v, viewHolder, p)
            }
            false
        })
    }

    interface OnItemClickListener {
        fun onItemClick(
            view: View,
            holder: ViewHolder,
            position: Int
        )

        fun onItemLongClick(
            view: View,
            holder: ViewHolder,
            position: Int
        ): Boolean
    }

    fun setOnItemClickListener(onItemClickListener: OnItemClickListener?) {
        mOnItemClickListener = onItemClickListener
    }

    fun addHeaderView(view: View?) {
        headerView = view
    }

    fun setCanLoadMore(canLoadMore: Boolean) {
        this.canLoadMore = canLoadMore
    }

    private var emptyText: String? = null
    private var emptyRes = R.drawable.icon_empty_default
    fun setEmptyContent(txt: String?, res: Int) {
        emptyText = txt
        emptyRes = res
    }

    fun setEmptyRes(emptyRes: Int) {
        this.emptyRes = emptyRes
    }

    fun setEmptyText(emptyText: String?) {
        this.emptyText = emptyText
    }

    companion object {
        const val TYPE_NORMAL = 100
        const val TYPE_HEAD = 101
        const val TYPE_LOAD_MORE = 102
    }

    init {
        //监听recylerview的滑动
        recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
            override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
                super.onScrolled(recyclerView, dx, dy)
                if (dy <= 0) {
                    return
                }
                if (loadMoreComplete && canLoadMore && !isLoading) {
                    var lastVisibleItem = 0
                    val layoutManager = recyclerView.layoutManager
                    if (layoutManager is LinearLayoutManager) {
                        lastVisibleItem = layoutManager.findLastVisibleItemPosition()
                    } else if (layoutManager is GridLayoutManager) {
                        lastVisibleItem = layoutManager.findLastVisibleItemPosition()
                    } else if (layoutManager is StaggeredGridLayoutManager) {
                        if (lastPositions == null) {
                            lastPositions = IntArray(layoutManager.spanCount)
                        }
                        layoutManager.findLastVisibleItemPositions(lastPositions)
                        lastVisibleItem = findMax(lastPositions!!)
                    } else {
                        throw RuntimeException(
                            "Unsupported LayoutManager used. Valid ones are LinearLayoutManager, GridLayoutManager and StaggeredGridLayoutManager"
                        )
                    }
                    if (lastVisibleItem + 1 == itemCount) {
                        loadMore()
                    }
                }
            }
        })
    }
}

该adapter分别可以适配线性列表,grid列表,瀑布流列表三种布局的加载更多。
使用方法:线性列表

 val layoutManager = LinearLayoutManager(this); //线性布局
        recyclerview.layoutManager = layoutManager
        homeAdapter = object: RVLoadMoreAdapter(this@AdapterMoreLoad1Activity,recyclerview,R.layout.item_rv_txt, mDatas){
            override fun convert(holder: RViewHolder, t: String, position: Int) {
                holder.setText(R.id.txt,mDatas[position])
            }

        }

        recyclerview.adapter = homeAdapter

        homeAdapter!!.setOnItemClickListener(object: RVLoadMoreAdapter.OnItemClickListener{
            override fun onItemClick(view: View, holder: RecyclerView.ViewHolder, position: Int) {
                
            }

            override fun onItemLongClick(
                view: View,
                holder: RecyclerView.ViewHolder,
                position: Int
            ): Boolean {
                return false
            }

        })
 homeAdapter!!.setLoadingMore(object: RVLoadMoreAdapter.OnLoadingMore{
            override fun onLoadMore() {
                downJson(mCurrentPage+1)
            }

        })

在downjson是可以是接口获取数据,获取完数据需要做一些操作,如下

 private fun downJson(page: Int) {

        Handler().postDelayed(Runnable {
            swipe_layout.isRefreshing = false
            if(page == 1){
                mDatas.clear()
                homeAdapter!!.setLoadMoreComplete(true)
            }
            mCurrentPage = page
            val datalist = ArrayList()

            if(page == 3){ //模拟滑动到最底部
                for (i in 1..7){
                    datalist.add("RecyclerView使用$i")
                }
            }else{
                for (i in 1..20){
                    datalist.add("RecyclerView使用$i")
                }
            }
            mDatas.addAll(datalist)
            if (datalist.size < 20) {
                homeAdapter!!.setLoadMoreComplete(false)
            }

            homeAdapter!!.notifyDataSetChanged()
            homeAdapter!!.Loading(false)
        },1000)

    }

具体操作大家可以自己分析,还是很容易理解。

这里特别注意:用grid列表的时候需要加入

layoutManager.spanSizeLookup = object: GridLayoutManager.SpanSizeLookup() {
            override fun getSpanSize(position: Int): Int {
                return if (homeAdapter!!.getItemViewType(position) == RVLoadMoreAdapter.TYPE_LOAD_MORE) {
                    2
                } else {
                    1
                }
            }

        }

这样加载更多的底部布局才能跨列显示。上面的2是因为我用的是2列的grid,如果是3列就是3,以此类推。

瀑布流的时候,需要重写onViewHolderCreated的方法,解决加载更多的跨列问题,如下

homeAdapter = object: RVLoadMoreAdapter(this@AdapterMoreLoad3Activity,recyclerview,R.layout.item_rv_txt, mDatas){

            override fun onViewHolderCreated(holder: RViewHolder, itemView: View, viewType: Int) {
                super.onViewHolderCreated(holder, itemView, viewType)
                if (viewType === TYPE_LOAD_MORE) {
                    val lp = holder.itemView.layoutParams
                    if (lp != null && lp is StaggeredGridLayoutManager.LayoutParams) {
                        lp.isFullSpan = true
                    }
                }
            }

            override fun convert(holder: RViewHolder, t: String, position: Int) {
                holder.setText(R.id.txt,mDatas[position])
            }

        }

github地址:https://gitee.com/stonezry/AndroidDemo

你可能感兴趣的:(recyclerview实现加载更多)