?项目需求实现让用户无感的加载更多的功能,不重复造轮子,在Github找到如下几种方案
因为在SmartRefreshLayout中调用autoLoadMore方法后,是会直接把footer显示在布局下面,而不是滚动到列表最后面开始,或隐藏动画加载。
自定义实现的autoLoadMoreNoSense方法对于autoloadmore修改并不多,只是把显示footer的动画操作移除,然后状态改变后,没有调用setStateLoading方法,使用的自定义的setStateLoadingNoSpinner方法。
需要注意的是在setStateLoadingNoSpinner方法中的这段:
mFooterLocked = false
?在调用setStateDirectLoading后,会将该属性设为true,锁定footer控件,然后再滚动的时候会触发嵌套滑动,将触摸事件传递到父控件去。所以在该方法执行完后要将mfooterLocked属性改回来。触发这里的嵌套滑动,有兴趣的可以去查一下“嵌套滑动”的机制。
以下代码是PreloadSmartLayout的实现。
class PreloadSmartLayout constructor(context: Context, attrs: AttributeSet?) :
SmartRefreshLayout(context, attrs) {
constructor(context: Context) : this(context, null)
fun autoLoadMoreNosense(): Boolean {
if (mState == RefreshState.None && (isEnableRefreshOrLoadMore(mEnableLoadMore) && !mFooterNoMoreData)) {
setViceState(RefreshState.Loading)
reboundAnimator = reboundAnimator?.run {
duration = 0
cancel()
null
}
mKernel.setState(RefreshState.PullUpToLoad)
if (mRefreshFooter != null) {
if (mState != RefreshState.ReleaseToLoad) {
mKernel.setState(RefreshState.ReleaseToLoad)
}
setStateLoadingNoSpinner()
} else {
mKernel.setState(RefreshState.None)
}
return true
} else {
return false
}
}
private fun setStateLoadingNoSpinner() {
notifyStateChanged(RefreshState.LoadReleased)
setStateDirectLoading(true)
// 在调用setStateDirectLoading方法后,mFooterLocked会变为true,表示footer被锁定,
// 此时上拉会触发嵌套滚动,滚动的是父控件而非列表,会让footer提前展示出来
mFooterLocked = false
val maxDragHeight: Float =
if (mFooterMaxDragRate < 10) mFooterHeight * mFooterMaxDragRate else mFooterMaxDragRate
if (mRefreshFooter is ClassicsFooter) {
(mRefreshFooter as ClassicsFooter).onReleased(
this,
mFooterHeight,
maxDragHeight.toInt()
)
}
}
}
然后怎么使用是参考了?BaseRecyclerViewAdapterHelper中的实现,在onBindViewHolder中的position到达自己设定的预加载标志时回调事件,然后调用autoLoadMoreNoSence。如下是BRVAH中的实现
?注意:在收到adapter中预加载回调时要判断当前的加载状态,因为该回调会被调用多次。
下面是我的Fragment中的列表实现:
private fun bindList() {
binding.listParent.apply {
setRefreshHeader(
ClassicsHeader(requireContext()),
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT
)
setRefreshFooter(
ClassicsFooter(requireContext()),
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT
)
setEnableAutoLoadMore(false) // 关闭列表滚动时自动触发加载更多
setEnableOverScrollDrag(false) // 设置是否启用越界拖动(仿苹果效果)
setEnableOverScrollBounce(false) // 是否启用越界回弹
}.setOnRefreshLoadMoreListener(object : OnRefreshLoadMoreListener {
override fun onRefresh(refreshLayout: RefreshLayout) {
viewModel.refreshList()
}
override fun onLoadMore(refreshLayout: RefreshLayout) {
LogUtils.d("onLoadMore()")
viewModel.loadMore()
}
})
binding.recyclerList.adapter = MyAdapter(R.layout.layout_item)
.apply {
setOnItemClickListener { item, _ ->
navToDetail(item.id)
}
openPreload(5, object : OnPreLoadListener {
override fun onPreload() {
binding.listParent.run {
if (!isLoading) { // 这里需要判断加载状态,因为会被多次调用
autoLoadMoreNosense()
}
}
}
})
}
}
以上功能目前只实现了demo,没有导入到正式项目中验证。如果有发现BUG请及时指出来,赠人玫瑰手有余香,互相帮助。
End
|