RecyclerView.OnScrollListener:为一次滚动实例多次调用

时间:2018-03-07 12:02:44

标签: android android-recyclerview

我有一个水平布局的recyclerview,一次只能看到一个视图:

mRecyclerView = findViewById(R.id.rvmain);
mRecyclerView.setOnFlingListener(null);
final SnapHelper snapHelper = new LinearSnapHelper();
snapHelper.attachToRecyclerView(mRecyclerView);
mLayoutManager = new LinearLayoutManager(this,LinearLayoutManager.HORIZONTAL,false);
mRecyclerView.setLayoutManager(mLayoutManager);
mAdapter = new MainActivityRVAdapter(postsModels,MainActivity.this);
mRecyclerView.setAdapter(mAdapter);

使用onScrolllistener,每次滚动我想知道起始位置和结束位置。我使用以下代码:

    @Override
    public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
        super.onScrollStateChanged(recyclerView, newState);


        if(count == 0) {
            View centerView = snapHelper.findSnapView(mLayoutManager);
            if(centerView != null){
                initial_position = mLayoutManager.getPosition(centerView);
                //initial_position2 = ((LinearLayoutManager)mRecyclerView.getLayoutManager()).findFirstVisibleItemPosition();
                Log.e("Initial Item Position:",""+initial_position);
                //Log.e("Initial Item Position2:",""+initial_position2);
            }
            count ++;
        }



        // get newstate position
        if(newState == AbsListView.OnScrollListener.SCROLL_STATE_IDLE) {
            View centerView = snapHelper.findSnapView(mLayoutManager);
            if(centerView != null){
                int pos = mLayoutManager.getPosition(centerView);

                count = 0; // in idle state clear the count again
                Log.e("Snapped Item Position:",""+pos);
            }
        }


    }

我得到的结果是:

E/Initial Item Position:: 0
E/Snapped Item Position:: 1
E/Initial Item Position:: 1
E/Snapped Item Position:: 1
E/Initial Item Position:: 1
E/Snapped Item Position:: 1
E/Initial Item Position:: 1
E/Snapped Item Position:: 1

它会多次返回头寸。我想检查最终和初始职位之间的区别。 我只想要开始和结束,以便我可以比较和检查,即:

E/Initial Item Position:: 0 and

E/Snapped Item Position:: 1

3 个答案:

答案 0 :(得分:0)

我遇到了同样的问题。而我发现: RecyclerView.OnScrollListeneronScrolled(...)SCROLL_STATE_DRAGGING期间多次呼叫SCROLL_STATE_SETTLING

我开始聆听第二次回调:
onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState)
在最终状态SCROLL_STATE_IDLE中,我们很有趣。

因此,在这种情况下,我们必须覆盖onScrollStateChanged(...),检查并忽略SCROLL_STATE_IDLE以外的所有状态,并在空闲时获得最终位置。

但是如docsonScrolled(...)

所述
  如果布局后可见项范围发生变化,也会调用

  计算。在这种情况下,dx和dy将为0。

在实践中,我发现如果我们调用adapter.notifyDataSetChanged()并且可见位置是“ 0 ”(即首次启动),onScrollStateChanged(...)将不会被调用,{{ 1}}将被 dx == dy == 0 调用一次。

最终的变体如下:

onScrolled(...)

答案 1 :(得分:0)

我遇到了同样的问题,并且我认识到导致问题的原因是快照帮助程序。我想这是因为在滚动完成后,捕捉帮助器会触发第二个小动作。因此onScrollStateChanged被调用两次。

幸运的是,现在有了ViewPager2。因此,我不必费劲去听快照。因为一次也有一个可见的视图,所以我用ViewPager2替换了Recyclerview,而不是Recyclerview.OnScrollListener,而是使用了ViewPager2.OnPageChangeCallback。那解决了问题。

答案 2 :(得分:0)

原因:

当你在 RecyclerView 上滚动时,它最终会触发一个 SCROLL_STATE_IDLE 事件,这是由于你的动作是你扔了,然后你放开了 RecyclerView

SnapHelper 将侦听 RecyclerView 的第一个 SCROLL_STATE_IDLE 事件,以便它可以准备计算 IT 需要滚动到目标 View,当它这样做时,它会第二次触发 SCROLL_STATE_IDLE 事件,因为 SnapHelper 正在“帮助”您滚动它。

================================================ ==================

解决方案:

您可以创建一个全局变量并将其用作“标志”,这将避免它被多次调用。最终代码将如下所示:

private boolean isFirstTimeCall = true;

recyclerViewExample.addOnScrollListener(new RecyclerView.OnScrollListener() {
        @Override
        public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
            super.onScrollStateChanged(recyclerView, newState);

            if (newState == RecyclerView.SCROLL_STATE_IDLE) {
                if (isFirstTimeCall) {
                    isFirstTimeCall = false;

                    // Do your stuff here...
            }

            if (newState == RecyclerView.SCROLL_STATE_DRAGGING) {
                isFirstTimeCall = true;
            }
        }
    });