總所周知,我們一般用LayoutManage的邊檢檢測方法來確定髓梅,是否觸底或者觸頂,如下:
!recyclerView.canScrollVertically(-1):檢測是否到達(dá)頂部。
!recyclerView.canScrollVertically(1):檢測是否到達(dá)底部圆仔。
但是問題來了,當(dāng)你手指松開后如果RecycleView滾動可能發(fā)生了超出內(nèi)容范圍(例如過滾動或彈性滾動)蔫劣,那么這時調(diào)用canScrollVertically(xxx)得到值并不準(zhǔn)確坪郭。
另外,我們可能還會用各種自定義計算的方式來檢測是否觸底或者觸頂脉幢,比如歪沃,滑動后檢測第一條數(shù)據(jù)的頂部是否觸達(dá)了頁面里上一個view的底部附近,或者檢測最后一條數(shù)據(jù)是否到觸達(dá)了屏幕的高度嫌松,但是很不幸沪曙,因為RecycleView的回收機制已經(jīng)各種case下,無論是val view = LayoutManage.findFirstVisibleItemPosition()還是val view = RecycleView.findItemViewByPosition(),總有一個時刻萎羔,view是null液走,其實無法時刻精準(zhǔn)。
經(jīng)過多種方案的嘗試改進方案,只有該方案比較精準(zhǔn):
結(jié)合 RecyclerView.computeVerticalScrollOffset 和滾動狀態(tài)
使用 computeVerticalScrollOffset 獲取滾動的精確偏移量贾陷,并結(jié)合 RecyclerView.OnScrollListener 檢測滾動狀態(tài)缘眶,確保能準(zhǔn)確檢測到觸摸松開后RecyclerView 的慣性滾動狀態(tài)和實時的偏移值的一系列行為是否到達(dá)邊界。
computeVerticalScrollOffset:
直接返回 RecyclerView 的當(dāng)前滾動偏移量髓废,無需累積巷懈。
值始終精確反映當(dāng)前滾動的位置,不會受邊界條件的影響
//如果是檢測是否觸底的話那么需要刪除@Check_2的部分慌洪,采用@Check_1(因為觸底檢測必須在SCROLL_STATE_IDLE狀態(tài)下)顶燕,
反之如果是要檢測Item數(shù)量是否已超出屏幕底部,那么刪除@Check_1的部分蒋譬,采用@Check_2割岛,否則不夠縱向絲滑。
private var scrollingDirection: ScrollingDirection = ScrollingDirection.NONE
private enum class ScrollingDirection {
SCROLLED_DOWN, SCROLLED_UP, NONE // We don't care about horizontal scroll for now
}
recyclerView?.setOnTouchListener { _, event ->
when (event.action) {
MotionEvent.ACTION_MOVE -> {
if (previousY <= 0f) {
previousY = event.y
}
val deltaY = event.y - previousY
if (deltaY > 0) {
scrollingDirection = ScrollingDirection.SCROLLED_UP
Log.d("logTag","ACTION_MOVE down: deltaY=$deltaY")
} else if (deltaY < 0) {
scrollingDirection = ScrollingDirection.SCROLLED_DOWN
Log.d("logTag","ACTION_MOVE up: deltaY=$deltaY")
}
previousY = event.y
}
//@Check_1-----start
MotionEvent.ACTION_UP,MotionEvent.ACTION_CANCEL -> {
//Replace with Your true condition.
//Maybe 'LayoutManage.findLastVisibleItemPosition()' used here
//to generate condition of 'shouldCollapse'.
val shouldCollapse = true
if (shouldCollapse) {
//collapseIfNeeded()
}
}
//@Check_1-----end
}
false
}
recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
super.onScrollStateChanged(recyclerView, newState)
// Detect state of stopping scrolling.
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
val offset = recyclerView.computeVerticalScrollOffset()
val extent = recyclerView.computeVerticalScrollExtent()
val range = recyclerView.computeVerticalScrollRange()
if (offset == 0) {
println("Reached the top")
//expandIfNeeded()
}
//@Check_2-----start
else if (offset + extent == range) {
println("Reached the bottom")
//collapseIfNeeded()
}
//@Check_2-----end
//reset value.
previousY = 0f
scrollingDirection = ScrollingDirection.NONE
}
}
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
// Print scrolling offset on time
val currentOffset = recyclerView.computeVerticalScrollOffset()
println("Current Scroll Offset: $currentOffset")
}
})
拓展:
1.當(dāng)RecycleView已經(jīng)觸底/觸頂時犯助,這時繼續(xù)向上/向下滑動時癣漆,onScrolled()方法不會被調(diào)用.
2.findLastVisibleItemPosition()方法還比較準(zhǔn),不是’findLastCompleteVisibleItemPosition()‘這個精確度似乎差點意思
-----------------------------End-----------------------------