前言
本文参考辉哥的博客RecyclerView更全解析之 - 打造通用的下拉刷新上拉加载进行实现,具体代码实现思路可查看原博客,目的是通过自定义RecyclerView
自己实现添加头部
、添加底部
、上拉加载
、下拉刷新
功能。
最终效果
具体实现
- 自定义支持添加头部和底部的Adapter
/**
- 支持添加头部和底部的Adapter
- on 2022/11/7
*/
class WrapRecyclerAdapter(adapter: RecyclerView.Adapter<RecyclerView.ViewHolder>) :
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
/**
* 用来存放头部和底部的集合
*/
private var headerView: SparseArray<View>
private var footerView: SparseArray<View>
//头部类型开始位置,用于viewType
private var BASE_ITEM_TYPE_HEADER = 1000000
//底部类型开始位置,用于viewType
private var BASE_ITEM_TYPE_FOOTER = 2000000
/**
* 列表的adapter
*/
private var adapter: RecyclerView.Adapter<RecyclerView.ViewHolder>
init {
this.adapter = adapter
headerView = SparseArray()
footerView = SparseArray()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
if (isHeaderViewType(viewType)) {
val headerView = headerView.get(viewType)
return createHeaderFooterViewHolder(headerView)
}
if (isFooterViewType(viewType)) {
val footerView = footerView.get(viewType)
return createHeaderFooterViewHolder(footerView)
}
return adapter.onCreateViewHolder(parent, viewType)
}
/**
* 创建头部或底部的ViewHolder
*/
private fun createHeaderFooterViewHolder(view: View): RecyclerView.ViewHolder {
return object : RecyclerView.ViewHolder(view) {}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
//如果是头部或者底部item,不进行布局绑定
if (isHeaderViewPosition(position) || isFooterViewPosition(position)) {
return
}
val itemAdapterPosition = position - headerView.size()
adapter.onBindViewHolder(holder, itemAdapterPosition)
}
override fun getItemViewType(position: Int): Int {
if (isHeaderViewPosition(position)) {
//如果是headerView
return headerView.keyAt(position)
}
if (isFooterViewPosition(position)) {
//如果是footerView
val footerPosition = position - headerView.size() - adapter.itemCount
return footerView.keyAt(footerPosition)
}
//则为普通adapter的ViewType
val adapterPosition = position - headerView.size()
return adapter.getItemViewType(adapterPosition)
}
override fun getItemCount(): Int {
//条目为三者数量之和
return adapter.itemCount + headerView.size() + footerView.size()
}
fun addHeaderView(view: View) {
val position = headerView.indexOfValue(view)
if (position < 0) {
headerView.put(BASE_ITEM_TYPE_HEADER++, view)
}
notifyDataSetChanged()
}
fun removeHeaderView(view: View) {
val position = headerView.indexOfValue(view)
if (position < 0) {
return
}
headerView.removeAt(position)
notifyDataSetChanged()
}
fun getAdapter(): RecyclerView.Adapter<ViewHolder> {
return adapter
}
fun addFooterView(view: View) {
val position = footerView.indexOfValue(view)
if (position < 0) {
footerView.put(BASE_ITEM_TYPE_FOOTER++, view)
}
notifyDataSetChanged()
}
fun removeFooterView(view: View) {
val position = footerView.indexOfValue(view)
if (position < 0) {
return
}
footerView.removeAt(position)
notifyDataSetChanged()
}
private fun isHeaderViewType(viewType: Int): Boolean {
val position = headerView.indexOfKey(viewType)
return position >= 0
}
private fun isFooterViewType(viewType: Int): Boolean {
val position = footerView.indexOfKey(viewType)
return position >= 0
}
private fun isHeaderViewPosition(position: Int): Boolean {
return position < headerView.size()
}
private fun isFooterViewPosition(position: Int): Boolean {
return position >= headerView.size() + adapter.itemCount
}
/**
* 解决GridLayoutManager添加头部和底部不占用一行的问题
*/
fun adjustSpanSize(recyclerView: RecyclerView) {
if (recyclerView.layoutManager is GridLayoutManager) {
val layoutManager = recyclerView.layoutManager as GridLayoutManager
layoutManager.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {
override fun getSpanSize(position: Int): Int {
val isHeaderOrFooter =
isHeaderViewPosition(position) || isFooterViewPosition(position)
return if (isHeaderOrFooter) {
layoutManager.spanCount
} else {
1
}
}
}
}
}
- 自定义可以添加头部和底部的RecyclerView
/**
- 可以添加头部和底部的RecyclerView
- on 2022/11/7
*/
open class WrapRecyclerView : RecyclerView {
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(
context,
attrs,
defStyleAttr
)
/**
* 包裹了头部和底部的adapter
*/
private var wrapRecyclerAdapter: WrapRecyclerAdapter? = null
/**
* 列表对应的list
*/
private var mAdapter: Adapter<ViewHolder>? = null
/**
* 增加一些通用功能
* 空列表数据应该显示emptyView
* 正在加载数据页面
*/
private var emptyView: View? = null
private var loadView: View? = null
private var mDataObserver = object : AdapterDataObserver() {
override fun onChanged() {
if (mAdapter == null) {
return
}
//观察者,列表adapter更新,包裹的也需要更新
if (wrapRecyclerAdapter != adapter) {
wrapRecyclerAdapter?.notifyDataSetChanged()
}
dataChanged()
}
override fun onItemRangeRemoved(positionStart: Int, itemCount: Int) {
if (mAdapter == null) {
return
}
if (wrapRecyclerAdapter != adapter) {
wrapRecyclerAdapter?.notifyItemRangeRemoved(positionStart, itemCount)
}
dataChanged()
}
override fun onItemRangeChanged(positionStart: Int, itemCount: Int) {
if (mAdapter == null) {
return
}
if (wrapRecyclerAdapter != adapter) {
wrapRecyclerAdapter?.notifyItemChanged(positionStart, itemCount)
}
dataChanged()
}
override fun onItemRangeChanged(positionStart: Int, itemCount: Int, payload: Any?) {
if (mAdapter == null) {
return
}
if (wrapRecyclerAdapter != adapter) {
wrapRecyclerAdapter?.notifyItemRangeChanged(positionStart, itemCount, payload)
}
dataChanged()
}
override fun onItemRangeInserted(positionStart: Int, itemCount: Int) {
if (mAdapter == null) {
return
}
if (wrapRecyclerAdapter != adapter) {
wrapRecyclerAdapter?.notifyItemRangeInserted(positionStart, itemCount)
}
dataChanged()
}
override fun onItemRangeMoved(fromPosition: Int, toPosition: Int, itemCount: Int) {
if (mAdapter == null) {
return
}
if (wrapRecyclerAdapter != adapter) {
wrapRecyclerAdapter?.notifyItemRangeRemoved(fromPosition, toPosition)
}
dataChanged()
}
}
private fun dataChanged() {
if (adapter?.itemCount == 0) {
emptyView?.visibility = VISIBLE
}
}
fun addEmptyView(view: View) {
this.emptyView = view
}
fun addLoadingView(loadingView: View) {
this.loadView = loadingView
loadingView.visibility = VISIBLE
}
override fun setAdapter(adapter: Adapter<*>?) {
//防止多次设置Adapter
if (mAdapter != null) {
mAdapter!!.unregisterAdapterDataObserver(mDataObserver)
mAdapter = null
}
this.mAdapter = adapter as Adapter<ViewHolder>?
wrapRecyclerAdapter = if (adapter is WrapRecyclerAdapter) {
adapter
} else {
WrapRecyclerAdapter(adapter as Adapter<ViewHolder>)
}
super.setAdapter(wrapRecyclerAdapter)
//注册一个观察者
mAdapter!!.registerAdapterDataObserver(mDataObserver)
//解决GridLayoutManager添加头部和底部不占据一行问题
wrapRecyclerAdapter!!.adjustSpanSize(this)
//加载数据页面
if (loadView != null && loadView!!.visibility == View.VISIBLE) {
loadView?.visibility = GONE
}
}
/**
* 添加头部
*/
fun addHeaderView(view: View) {
wrapRecyclerAdapter?.addHeaderView(view)
}
/**
* 添加底部
*/
fun addFooterView(view: View) {
wrapRecyclerAdapter?.addFooterView(view)
}
fun removeHeaderView(view: View) {
wrapRecyclerAdapter?.removeHeaderView(view)
}
fun removeFooterView(view: View) {
wrapRecyclerAdapter?.removeFooterView(view)
}
- 为了更好的扩展下拉刷新,新增下拉刷新辅助抽象类
/**
- 下拉刷新的辅助类
- on 2022/11/7
*/
abstract class RefreshViewCreator {
/**
* 获取下拉刷新的View
* @param context 上下文参数
* @param parent 父容器 RecyclerView
*/
abstract fun getRefreshView(context: Context, parent: ViewGroup): View
/**
* 正在下拉
* @param currentDragHeight 当前拖动的高度
* @param refreshViewHeight 整体刷新View的高度
* @param currentRefreshStatus 当前状态
*
*/
abstract fun onPull(currentDragHeight: Int, refreshViewHeight: Int, currentRefreshStatus: Int)
/**
* 正在刷新中
*/
abstract fun onRefreshing()
/**
* 停止刷新
*/
abstract fun onStopRefresh()
}
- 自定义支持下拉刷新的
RefreshRecyclerView
/**
- 下拉刷新的RecyclerView
- on 2022/11/7
*/
open class RefreshRecyclerView : WrapRecyclerView {
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(
context, attrs, defStyleAttr
)
//下拉刷新的辅助类
private var refreshCreator: RefreshViewCreator? = null
//下拉刷新头部的高度
private var refreshViewHeight = 0
//下拉刷新的头部View
private var refreshView: View? = null
//手指按下Y的位置
private var fingerDownY = 0
//手指拖拽的阻力指数
open var dragIndex = 0.35f
//当前是否正在拖动
private var currentDrag = false
//当前状态
private var currentRefreshStatus = 0
// 默认状态
private val REFRESH_STATUS_NORMAL = 1
//下拉刷新状态
private val REFRESH_STATUS_PULL_DOWN_REFRESHING = 2
//松开刷新状态
private val REFRESH_STATUS_LOOSEN_REFRESHING = 3
//正在刷新状态
private val REFRESH_STATUS_REFRESHING = 4
fun addRefreshViewCreator(refreshViewCreator: RefreshViewCreator) {
this.refreshCreator = refreshViewCreator
addRefreshView()
}
override fun setAdapter(adapter: Adapter<*>?) {
super.setAdapter(adapter)
addRefreshView()
}
override fun dispatchTouchEvent(ev: MotionEvent): Boolean {
when (ev.action) {
MotionEvent.ACTION_DOWN -> {
//记录手指按下的位置
fingerDownY = ev.rawY.toInt()
}
MotionEvent.ACTION_UP -> {
if (currentDrag) {
restoreRefreshView()
}
}
}
return super.dispatchTouchEvent(ev)
}
/**
* 重置当前刷新状态
*/
private fun restoreRefreshView() {
val currentTopMargin = (refreshView?.layoutParams as MarginLayoutParams).topMargin
var finalTopMargin = -refreshViewHeight + 1
if (currentRefreshStatus == REFRESH_STATUS_LOOSEN_REFRESHING) {
finalTopMargin = 0
currentRefreshStatus = REFRESH_STATUS_REFRESHING
refreshCreator?.onRefreshing()
listener?.onRefresh()
}
val distance = currentTopMargin - finalTopMargin
//回弹到指定位置
val animator: ValueAnimator =
ObjectAnimator.ofFloat(currentTopMargin.toFloat(), finalTopMargin.toFloat())
.setDuration(distance.toLong())
animator.addUpdateListener {
val currentTopMargin = it.animatedValue as Float
setRefreshViewMarginTop(currentTopMargin.toInt())
}
animator.start()
currentDrag = false
}
override fun onTouchEvent(ev: MotionEvent): Boolean {
when (ev.action) {
MotionEvent.ACTION_MOVE -> {
//在最顶部的时候才处理,否则不需要处理
if (canScrollUp() || currentRefreshStatus == REFRESH_STATUS_REFRESHING || refreshView == null || refreshCreator == null) {
//如果没有到达最顶端,也就是说还可以向上滚动就什么都不处理
return super.onTouchEvent(ev)
}
//解决下拉刷新自动滚动问题
if (currentDrag) {
scrollToPosition(0)
}
//获取手指触摸拖拽的距离
val distanceY = (ev.rawY - fingerDownY) * dragIndex
//如果是已经到达头部,并且不断的向上拉,那么不断的改变refreshView的marginTop的值
if (distanceY > 0) {
val marginTop = distanceY - refreshViewHeight
setRefreshViewMarginTop(marginTop.toInt())
updateRefreshStatus(distanceY)
currentDrag = true
return false
}
}
}
return super.onTouchEvent(ev)
}
/**
* 更新刷新状态
*/
private fun updateRefreshStatus(distanceY: Float) {
currentRefreshStatus = if (distanceY <= 0) {
REFRESH_STATUS_NORMAL
} else if (distanceY < refreshViewHeight) {
REFRESH_STATUS_PULL_DOWN_REFRESHING
} else {
REFRESH_STATUS_LOOSEN_REFRESHING
}
refreshCreator?.onPull(distanceY.toInt(), refreshViewHeight, currentRefreshStatus)
}
/**
* 添加头部刷新View
*/
private fun addRefreshView() {
if (adapter != null && refreshCreator != null) {
val refreshView = refreshCreator?.getRefreshView(context, this)
if (refreshView != null) {
addHeaderView(refreshView)
this.refreshView = refreshView
}
}
}
override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
super.onLayout(changed, l, t, r, b)
if (refreshView != null && refreshViewHeight <= 0) {
//获取头部刷新View的高度
refreshViewHeight = refreshView?.measuredHeight!!
if (refreshViewHeight > 0) {
//隐藏头部刷新的View marginTop 多留出1px防止无法判断是不是滑动到头部问题
setRefreshViewMarginTop(-refreshViewHeight + 1)
}
}
}
private fun setRefreshViewMarginTop(marginTop: Int) {
var finalMarginTop = marginTop
val params = refreshView?.layoutParams as MarginLayoutParams
if (finalMarginTop < -refreshViewHeight + 1) {
finalMarginTop = -refreshViewHeight + 1
}
params.topMargin = finalMarginTop
refreshView?.layoutParams = params
}
private fun canScrollUp(): Boolean {
return canScrollVertically(-1) || scrollY > 0
}
fun onStopRefresh() {
currentRefreshStatus = REFRESH_STATUS_NORMAL
restoreRefreshView()
refreshCreator?.onStopRefresh()
}
private var listener: OnRefreshListener? = null
fun setOnRefreshListener(listener: OnRefreshListener) {
this.listener = listener
}
interface OnRefreshListener {
fun onRefresh()
}
- 具体的下拉刷新类以及布局文件
/**
* on 2022/11/7
*/
class CommonRefreshCreator : RefreshViewCreator() {
private var refreshView: View? = null
override fun getRefreshView(context: Context, parent: ViewGroup): View {
val view =
LayoutInflater.from(context).inflate(R.layout.layout_progressbar, parent,false)
refreshView = view.findViewById(R.id.pb)
return view
}
override fun onPull(currentDragHeight: Int, refreshViewHeight: Int, currentRefreshStatus: Int) {
val rotate = currentDragHeight / refreshViewHeight
//不断下拉的过程中不断旋转图片
refreshView!!.rotation = (rotate * 360).toFloat()
}
override fun onRefreshing() {
//刷新的时候也不断旋转
val animation = RotateAnimation(
0f,
720f,
Animation.RELATIVE_TO_SELF,
0.5F,
Animation.RELATIVE_TO_SELF,
0.5f
)
animation.repeatCount = -1
animation.duration = 2000
refreshView!!.startAnimation(animation)
}
override fun onStopRefresh() {
//停止的时候清除动画
refreshView!!.rotation = 0f
refreshView!!.clearAnimation()
}
}
### layout_progressbar
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="80dp">
<ProgressBar
android:indeterminateDuration="1000"
android:max="360"
android:id="@+id/pb"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_centerInParent="true" />
</RelativeLayout>
- 支持上拉加载下拉刷新的RecyclerView
/**
- 支持上拉加载 下拉刷新的RecyclerView
- on 2022/11/7
*/
class LoadRefreshRecyclerView : RefreshRecyclerView {
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(
context,
attrs,
defStyleAttr
)
//上拉加载更多的辅助类
private var loadViewCreator: LoadViewCreator? = null
//上拉加载更多头部的高度
private var loadViewHeight = 0
//上拉加载更多的头部View
private var loadView: View? = null
//手指按下的位置
private var fingerDownY = 0
//当前是否正在拖动
private var currentDrag = false
//当前状态
private var currentLoadStatus = 0
companion object{
//默认状态
var LOAD_STATUS_NORMAL = 10
//上拉加载更多状态
var LOAD_STATUS_PULL_DOWN_REFRESH = 11
//松开加载更多状态
var LOAD_STATUS_LOOSEN_LOADING = 12
//正在加载更多状态
var LOAD_STATUS_LOADING = 13
}
//设置上拉加载更多
fun addLoadViewCreator(loadViewCreator: LoadViewCreator) {
this.loadViewCreator = loadViewCreator
addLoadView()
}
override fun setAdapter(adapter: Adapter<*>?) {
super.setAdapter(adapter)
addLoadView()
}
override fun dispatchTouchEvent(ev: MotionEvent): Boolean {
when (ev.action) {
MotionEvent.ACTION_DOWN -> {
//记录手指按下的位置,之所以写在dispatchTouchEvent里是因为如果我们处理了item点击事件,那么就不会进入onTouchEvent里面,所有应该在这里处理
fingerDownY = ev.rawY.toInt()
}
MotionEvent.ACTION_UP -> {
if (currentDrag) {
restoreLoadView()
}
}
}
return super.dispatchTouchEvent(ev)
}
/**
* 重置上拉加载更多View
*/
private fun restoreLoadView() {
var currentBottomMargin = (loadView?.layoutParams as MarginLayoutParams).bottomMargin
var finalBottomMargin = 0
if (currentLoadStatus == LOAD_STATUS_LOOSEN_LOADING) {
currentLoadStatus = LOAD_STATUS_LOADING
loadViewCreator?.onLoading()
listener?.onLoad()
}
val distance = currentBottomMargin - finalBottomMargin
//回弹到指定位置
val animator =
ObjectAnimator.ofFloat(currentBottomMargin.toFloat(), finalBottomMargin.toFloat())
.setDuration(distance.toLong())
animator.addUpdateListener {
val currentTopMargin = it.animatedValue
setLoadViewMarginBottom(currentTopMargin as Float)
}
animator.start()
currentDrag = false
}
override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
super.onLayout(changed, l, t, r, b)
if (loadViewCreator != null && loadView != null) {
loadViewHeight = loadView!!.measuredHeight
}
}
override fun onTouchEvent(ev: MotionEvent): Boolean {
when (ev.action) {
MotionEvent.ACTION_MOVE -> {
//当在最底部的时候才处理,否则不需要处理
if (canScrollDown() || currentLoadStatus == LOAD_STATUS_LOADING) {
return super.onTouchEvent(ev)
}
//解决上拉加载更多自动滚动问题
if (currentDrag) {
scrollToPosition(adapter!!.itemCount - 1)
}
//获取手指触摸拖拽的距离
val distanceY = (ev.rawY - fingerDownY) * dragIndex
//如果是已经到达底部,并且不断的向下拉,那么不断的改变marginBottom的值
if (distanceY < 0) {
setLoadViewMarginBottom(-distanceY)
updateLoadStatus(-distanceY)
currentDrag = true
return true
}
}
}
return super.onTouchEvent(ev)
}
/**
* 设置加载View的marginBottom
*/
private fun setLoadViewMarginBottom(marginBottom: Float) {
var finalMarginBottom = marginBottom.toInt()
val marginLayoutParams = loadView!!.layoutParams as MarginLayoutParams
if (finalMarginBottom < 0) {
finalMarginBottom = 0
}
marginLayoutParams.bottomMargin = finalMarginBottom
loadView?.layoutParams = marginLayoutParams
}
private fun canScrollDown(): Boolean {
return canScrollVertically(1)
}
/**
* 停止加载更多
*/
fun onStopLoad() {
currentLoadStatus = LOAD_STATUS_NORMAL
restoreLoadView()
loadViewCreator?.onStopLoad()
}
private fun updateLoadStatus(distanceY: Float) {
currentLoadStatus = if (distanceY <= 0) {
LOAD_STATUS_NORMAL
} else if (distanceY < loadViewHeight) {
LOAD_STATUS_PULL_DOWN_REFRESH
} else {
LOAD_STATUS_LOOSEN_LOADING
}
loadViewCreator?.onPull(distanceY.toInt(), loadViewHeight, currentLoadStatus)
}
private fun addLoadView() {
if (adapter != null && loadViewCreator != null) {
//添加底部加载更多View
val view = loadViewCreator?.getLoadView(context, this)
if (view != null) {
addFooterView(view)
this.loadView = view
}
}
}
private var listener: OnLoadMoreListener? = null
fun setOnLoadMoreListener(listener: OnLoadMoreListener) {
this.listener = listener
}
interface OnLoadMoreListener {
fun onLoad()
}
}
- 上拉加载更多辅助抽象类
/**
- 上拉加载更多辅助类
- on 2022/11/8
*/
abstract class LoadViewCreator {
/**
* 获取上拉加载更多的View
*/
abstract fun getLoadView(context: Context, parent: ViewGroup): View
/**
* 正在上拉
* @param currentDragHeight 当前拖动的距离
* @param loadViewHeight 总的加载高度
* @param currentLoadStatus 当前状态
*/
abstract fun onPull(currentDragHeight: Int, loadViewHeight: Int, currentLoadStatus: Int)
/**
* 正在加载中
*/
abstract fun onLoading()
/**
* 停止加载
*/
abstract fun onStopLoad()
}
- 上拉加载更多具体实现类以及对应布局文件
class CommonLoadCreator : LoadViewCreator() {
private var tv: TextView? = null
private var pb: ProgressBar? = null
private var loadView: View? = null
override fun getLoadView(context: Context, parent: ViewGroup): View {
val loadView: View =
LayoutInflater.from(context).inflate(R.layout.layout_load_footer_view, parent, false)
tv = loadView.findViewById(R.id.tv)
pb = loadView.findViewById(R.id.pb)
this.loadView = loadView
return loadView
}
override fun onPull(currentDragHeight: Int, loadViewHeight: Int, currentLoadStatus: Int) {
if (currentLoadStatus == LoadRefreshRecyclerView.LOAD_STATUS_PULL_DOWN_REFRESH) {
tv?.text = "上拉加载更多"
}
if (currentLoadStatus == LoadRefreshRecyclerView.LOAD_STATUS_LOOSEN_LOADING) {
tv?.text = "松开加载更多"
}
}
override fun onLoading() {
tv?.visibility = View.GONE
pb?.visibility = View.VISIBLE
val animation = RotateAnimation(
0f,
720f,
Animation.RELATIVE_TO_SELF,
0.5f,
Animation.RELATIVE_TO_SELF,
0.5f
)
animation.duration = 2000
animation.repeatCount = -1
pb?.startAnimation(animation)
}
override fun onStopLoad() {
//停止加载的时候
pb?.rotation = 0f
pb?.clearAnimation()
pb?.visibility = View.GONE
tv?.text = "上拉加载更多"
tv?.visibility = View.VISIBLE
}
}
### layout_load_footer_view
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="60dp"
android:gravity="center">
<ProgressBar
android:id="@+id/pb"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_centerVertical="true"
android:indeterminateDuration="1000"
android:max="360" />
<TextView
android:id="@+id/tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="10dp"
android:layout_toRightOf="@+id/pb"
android:text="上拉加载更多" />
</RelativeLayout>
测试代码
class RecyclerActivity : AppCompatActivity() {
private val list = mutableListOf<String>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_recycler)
for (i in 0..50) {
list.add("$i")
}
val rlv = findViewById<LoadRefreshRecyclerView>(R.id.rlv)
rlv.layoutManager = GridLayoutManager(this, 4)
val adapter = CommonItemAdapter(this, list)
rlv.adapter = adapter
val headerView =
LayoutInflater.from(this).inflate(R.layout.layout_recycler_header, rlv, false)
val footerView =
LayoutInflater.from(this).inflate(R.layout.layout_recycler_footer, rlv, false)
//设置上拉刷新
rlv.addRefreshViewCreator(CommonRefreshCreator())
//添加Header
rlv.addHeaderView(headerView)
//添加Footer
rlv.addFooterView(footerView)
//添加下拉加载更多 【由于内部是通过addView实现,存在添加顺序,需要注意】
rlv.addLoadViewCreator(CommonLoadCreator())
rlv.setOnRefreshListener(object : RefreshRecyclerView.OnRefreshListener {
override fun onRefresh() {
rlv.postDelayed({
rlv.onStopRefresh()
}, 2000)
}
})
rlv.setOnLoadMoreListener(object : LoadRefreshRecyclerView.OnLoadMoreListener {
override fun onLoad() {
rlv.postDelayed({
rlv.onStopLoad()
}, 2000)
}
})
}
}
总结
通过自己动手实现一套下拉刷新上拉加载框架,了解了RecyclerView添加Header
以及Footer
的实现原理,通过本次学习也看到了代码剥离拆分以及设计模式运用的重要性,写代码一定要多思考,才能写出让人赏心悦目的代码。