Recyclerview 上拉加载更多

文章目录

  • 效果如下
  • 主要步骤
  • 封装前代码
    • 1.adapter中
    • 2.定义一个抽象类
    • 3.MainActivity中
  • 封装后代码
    • 1. LoadMoreWrapper
    • 2. Adapter
    • 3.Activity中


效果如下

主要步骤

实现上拉加载更多主要有3步

  1. 定义两个 item , 第一个是正常显示内容的 item ,第二个是显示正在加载视图的 item 。如果 Adapter 中(position + 1 == itemCount),则说明滑到了最下面,此时加载第二个布局。
  2. 在 onCreateViewHolder 中对 viewType 进行判断,根据情况返回两种不同的 ViewHolder。同样,在onBindViewHolder 中对两种情况作不同处理。
  3. 在 Activity 中对 recyclerview 的滑动事件进行监听,如果 recyclerview 滑动到最下面,则进行相应的逻辑处理。

封装前代码

1.adapter中

代码如下(示例):

class MyAdapter(val data : List<String>): RecyclerView.Adapter<RecyclerView.ViewHolder>(){
     
    private val footView = 1   // 定义变量,对应不同的情况
    private val normalView = 0
    private val footStart = 2
    private val footEnd = 3
    private val footNoMore = 4
    private var footState = 0

    class MyVH(view: View):RecyclerView.ViewHolder(view) {
       // 普通的ViewHolder
        val textNormal = view.findViewById<TextView>(R.id.textView)
    }

    class FootVH(view: View): RecyclerView.ViewHolder(view) {
       // 显示"正在加载中"界面的ViewHolder
        val textFoot = view.findViewById<TextView>(R.id.tv_my_more)
        val progressBar = view.findViewById<ProgressBar>(R.id.progressBar)
    }
    override fun getItemViewType(position: Int): Int {
       // 返回应该加载哪种类型的ViewHodler
        if (position + 1 == itemCount) {
       // 说明已经滑动到最底部了
            return footView
        } else {
     
            return normalView
        }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
      // 创建不同的ViewHodler,但是都是继承自RecyclerView.ViewHolder
        if (viewType == normalView) {
     
            val view = LayoutInflater.from(parent.context).inflate(R.layout.item_text, parent, false) // 正常显示内容的 view
            return MyVH(view)
        }else {
     
            val view = LayoutInflater.from(parent.context).inflate(R.layout.item_more, parent, false) // footView
            return FootVH(view)
        }
    }

    override fun getItemCount(): Int {
      // 返回数据个数加1,因为多一个用来显示 “正在加载中”界面的item        
        return data.size + 1
    }


    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
     
        if (holder is MyVH) {
     
            holder.textNormal.text = data[position]
        } else if (holder is FootVH) {
     
            if (footState == 2) {
      // 正在加载中
                holder.textFoot.visibility = View.VISIBLE
                holder.progressBar.visibility = View.VISIBLE
            }else if (footState == 3) {
      // 加载结束
                holder.textFoot.visibility = View.GONE
                holder.progressBar.visibility = View.GONE
            }else if (footState == 4) {
      // 没有更多数据可以加载了
                holder.progressBar.visibility = View.GONE
                holder.textFoot.text = "没有更多数据啦"
            }
        }
    }

    fun setFootState(state: Int) {
      // 设置不同的 footState
        footState = state
        notifyDataSetChanged() // 更新 Adapter 数据
    }
}

2.定义一个抽象类

定义一个抽象类,减少Activity中对RecyclerView的监听代码

代码如下(示例):

abstract class EndRecyclerOnScrollListener: RecyclerView.OnScrollListener(){
     
    private var flag = 0

    override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
     
        super.onScrollStateChanged(recyclerView, newState)
        val layout = recyclerView.layoutManager as LinearLayoutManager
        val lastPositionCompletely = layout.findLastCompletelyVisibleItemPosition()
        if (lastPositionCompletely == layout.itemCount - 1 && flag == 0) {
     
            loadMore()
        }
    }

    abstract fun loadMore()

    fun setFlag(flag: Int) {
         // 设置标记防止多次向上滑动,多次调用 loadMore()
        this.flag = flag
    }
}

3.MainActivity中

class MainActivity : AppCompatActivity() {
     
    private val data = ArrayList<String>()

    override fun onCreate(savedInstanceState: Bundle?) {
     
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        recyclerView.layoutManager = LinearLayoutManager(this)
        getData()
        val adapter = MyAdapter(data)
        recyclerView.adapter = adapter
        recyclerView.addOnScrollListener(object : EndRecyclerOnScrollListener() {
     // 匿名内部类实现接口
            override fun loadMore() {
      // 具体获取数据的逻辑
                setFlag(1)  // 设置flag = 1,向上滑动,监听事件会继续触发,但是不会继续加载数据
                adapter.setFootState(2) // 设置 FootView 的初始状态
                Timer().schedule(object : TimerTask() {
      // 延时执行
                    override fun run() {
     
                        if (adapter.itemCount < 52) {
     
                            runOnUiThread{
     
                                getData()
                                adapter.setFootState(3) // 加载完成
                                setFlag(0) // 此次数据加载完毕,设置flag = 0,以便下次数据可以加载
                            }
                        }else {
     
                            runOnUiThread {
      
                                adapter.setFootState(4) // 没有更多数据加载了
                            }
                        }
                    }
                }, 1000)
            }

        })
    }

    fun getData() {
     
        var s = 'A'
        for (i in 0..25) {
     
            data.add(s.toString())
            s++
        }
    }
}

至此已经实现了上拉加载更多的功能,不过此时如果其他 RecyclerView 也要实现上拉加载更多,就要写许多重复代码在 Adapter 中,为了减少重复代码,下面对 Adapter 进行封装。

封装后代码

1. LoadMoreWrapper

class LoadMoreWrapper(private val adapter: RecyclerView.Adapter<RecyclerView.ViewHolder>) :
    RecyclerView.Adapter<RecyclerView.ViewHolder>() {
      // 因为不同Adapter的ViewHolder类型是不同的,但是都是继承自RecyclerView.ViewHolder,所以泛型指定为RecyclerView.ViewHolder
    private val footView = 1
    private val normalView = 0
    private val footStart = 2
    private val footEnd = 3
    private val footNoMore = 4
    private var footState = 0

    class FootVH(view: View) : RecyclerView.ViewHolder(view) {
     
        val textFoot = view.findViewById<TextView>(R.id.tv_my_more)
        val progressBar = view.findViewById<ProgressBar>(R.id.progressBar)
    }

    override fun getItemViewType(position: Int): Int {
     
        if (position + 1 == itemCount) {
     
            return footView
        } else {
     
            return normalView
        }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder{
     
        if (viewType == normalView) {
     
            return adapter.onCreateViewHolder(parent, viewType) // 调用adapter的onCreateViewHolder返会正常布局
        } else {
     
            val view =
                LayoutInflater.from(parent.context).inflate(R.layout.item_more, parent, false)
            return FootVH(view)
        }
    }

    override fun getItemCount(): Int {
     
        return adapter.itemCount + 1
    }

    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
     
        if (holder is FootVH) {
     
            if (footState == 2) {
     
                holder.textFoot.visibility = View.VISIBLE
                holder.progressBar.visibility = View.VISIBLE
            } else if (footState == 3) {
     
                holder.textFoot.visibility = View.GONE
                holder.progressBar.visibility = View.GONE
            } else if (footState == 4) {
     
                holder.progressBar.visibility = View.GONE
                holder.textFoot.text = "没有更多数据啦"
            }
        } else {
     
            adapter.onBindViewHolder(holder, position)
        }
    }

    fun setFootState(state: Int) {
     
        footState = state
        notifyDataSetChanged()
    }

}

2. Adapter

然后Adapter中的写法就是一般的写法了
class MyAdapter(val data : List): RecyclerView.Adapter(){

class MyVH(view: View):RecyclerView.ViewHolder(view) {
    val textNormal = view.findViewById(R.id.textView)
}

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyVH {
    val view = LayoutInflater.from(parent.context).inflate(R.layout.item_text, parent, false)
    return MyVH(view)
}

override fun getItemCount(): Int {
    return data.size
}

override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
    holder as MyVH
    holder.textNormal.text = data[position]
}

}

3.Activity中

class MainActivity : AppCompatActivity() {
     
    private val data = ArrayList<String>()

    override fun onCreate(savedInstanceState: Bundle?) {
     
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        recyclerView.layoutManager = LinearLayoutManager(this)
        getData()
        val adapter = MyAdapter(data)
        val loadMoreWrapper = LoadMoreWrapper(adapter) // 封装后的Adapter
        recyclerView.adapter = loadMoreWrapper
        recyclerView.addOnScrollListener(object : EndRecyclerOnScrollListener() {
      // 添加监听事件
            override fun loadMore() {
      // 加载逻辑
                setFlag(1)  // 设置flag = 1,向上滑动,监听事件会继续触发,但是不会继续加载数据
                loadMoreWrapper.setFootState(2)
                Timer().schedule(object : TimerTask() {
     
                    override fun run() {
     
                        if (adapter.itemCount < 100) {
     
                            runOnUiThread{
     
                                getData()
                                loadMoreWrapper.setFootState(3)
                                setFlag(0) // 此次数据加载完毕,设置flag = 0,以便下次数据可以加载
                            }
                        }else {
     
                            runOnUiThread{
     
                                loadMoreWrapper.setFootState(4)
                            }
                        }
                    }
                }, 1000)
            }
        })
    }

    fun getData() {
     
        var s = 'A'
        for (i in 0..25) {
     
            data.add(s.toString())
            s++
        }
    }
}

参考文章 https://www.jianshu.com/p/b502c5b59998

你可能感兴趣的:(Android知识点,UI,android)