圣者无名,大者无形。
鹰立如睡,虎行似病。
1. RecyclerView的滑动状态
RecyclerView在我们日常开发中,是必不可少的"神器"。有时候我们需要对其滚动过程进行监听,从而进行相应的一些操作。
常规操作:
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
// TODO 根据『newState』 to do sth...
}
}
关于RecycleView滑动状态:
/**
* 当前RecyclerView静止(当前不在滚动状态)
* The RecyclerView is not currently scrolling.
*/
public static final int SCROLL_STATE_IDLE = 0;
/**
* RecyclerView当前被拖拽滚动(简而言之,手指没有离开屏幕)
* The RecyclerView is currently being dragged by outside input such as user touch input.
*/
public static final int SCROLL_STATE_DRAGGING = 1;
/**
* RecyclerView当前正在设置动画到最终位置,不受外部控制(即:惯性滑动过程中)
* The RecyclerView is currently animating to a final position while not under
* outside control.
*/
public static final int SCROLL_STATE_SETTLING = 2;
2.遇到的问题
RecyclerView 只有滑动到中间位置会回调SCROLL_STATE_IDLE,而正常滑动到左右两边却不会触发。(PS:滑动到两边如果我们滑动幅度较大触发回弹效果,就能触发SCROLL_STATE_IDLE)
以下列举网上关于这种情况的讨论:
-
SCROLL_STATE_IDLE is never called in case of scrolling up #24
-
ListView does not report SCROLL_STATE_IDLE after SCROLL_STATE_TOUCH_SCROLL
3. 解决的思路
3.1. 思路正确,但解决不了问题
正常来讲,大多数人都很容易想到的方案,那就是在状态为SCROLL_STATE_SETTLING时,强制其停止,即直接调用stopScroll(),让其停止。(PS: 理想很丰满…)
3.2 完美解决方案
答案就在这里:真正能解决问题的链接
对于不能科学上网的同学,这里将两种方案搬到这里:
Answer 1
这里的高明之处在于: first + count > mListAdapter.getCount(),用来判断是否在边界位置。
mList.setOnScrollListener(new OnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
mListAdapter.setIsScrolling(scrollState != SCROLL_STATE_IDLE);
Log.i(this, "scrollStateChanged" + scrollState);
int first = view.getFirstVisiblePosition();
int count = view.getChildCount();
if (scrollState == SCROLL_STATE_IDLE || (first + count > mListAdapter.getCount()) ) {
mList.invalidateViews();
}
}
});
Answer 2
核心思想都是 想办法判断边界位置,这里提供了一种区别于Answer1的方法。具体就参考下面代码即可。
recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
super.onScrollStateChanged(recyclerView, newState)
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
// TODO sth
}
}
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
/* If the user scrolls to the edges of the recyclerview, we can't trust that we get the SCROLL_STATE_IDLE state.
* Therefore we have to update the view here in onScrolled for these cases
*/
if (!recyclerView.canScrollVertically(1) || !recyclerView.canScrollVertically(-1)) {
// TODO sth
}
}
}
希望大家别遇到这个问题…