RecyclerView不回调RecyclerView.SCROLL_STATE_IDLE的问题

本文详细探讨了RecyclerView在不同滑动状态下的行为特点,并针对滑动到边界时不触发SCROLL_STATE_IDLE状态的问题提供了两种有效解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

圣者无名,大者无形。
鹰立如睡,虎行似病。


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

以下列举网上关于这种情况的讨论:

  1. RecyclerView SCROLL_STATE_IDLE is being called late

  2. SCROLL_STATE_IDLE is never called in case of scrolling up #24

  3. 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
        }
    }
}

希望大家别遇到这个问题…

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值