Java RecyclerView 向上/向下滚动侦听器

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/29024058/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 07:12:51  来源:igfitidea点击:

RecyclerView scrolled UP/DOWN listener

javaandroidandroid-recyclerviewonscrolllistener

提问by Libin

How do we know if user scrolled down or up in RecyclerView?

我们如何知道用户是向下滚动还是向上滚动RecyclerView

I tried with RecyclerView#OnScrollListener, it gives the amount of vertical scroll and the scroll state. How do we get the last scroll position when started to dragging and scrolled position when scroll state idle.

我试过RecyclerView#OnScrollListener,它给出了垂直滚动的数量和滚动状态。我们如何在滚动状态空闲时开始拖动和滚动位置时获得最后的滚动位置。

Thank you.

谢谢你。

采纳答案by Xcihnegn

Try this way:

试试这个方法:

private static int firstVisibleInListview;

firstVisibleInListview = yourLayoutManager.findFirstVisibleItemPosition();

In your scroll listener:

在您的滚动侦听器中:

public void onScrolled(RecyclerView recyclerView, int dx, int dy) 
{
    super.onScrolled(recyclerView, dx, dy);

    int currentFirstVisible = yourLayoutManager.findFirstVisibleItemPosition();

    if(currentFirstVisible > firstVisibleInListview)
       Log.i("RecyclerView scrolled: ", "scroll up!");
    else
       Log.i("RecyclerView scrolled: ", "scroll down!");  

    firstVisibleInListview = currentFirstVisible;

}

回答by Reaz Murshed

The accepted answer works fine, but @MaciejPigulski gave more clear and neat solution in the comment below. I just putting it as an answer here. Here's my working code.

接受的答案工作正常,但@MaciejPigulski 在下面的评论中给出了更清晰、更简洁的解决方案。我只是把它作为答案放在这里。这是我的工作代码。

mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {

    @Override
    public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
        super.onScrolled(recyclerView, dx, dy);
        if (dy > 0) {
            // Scrolling up
        } else {
            // Scrolling down
        }
    }

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

        if (newState == AbsListView.OnScrollListener.SCROLL_STATE_FLING) {
            // Do something
        } else if (newState == AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL) {
            // Do something
        } else {
            // Do something
        }
    }
});

回答by Shahid Sarwar

I wanted to hide a layout if the recyclerview is scrolled down and then make it visible if the recyclerview is scrolled up. I did some thinking and came up with this logic. Variable y is a global static int. Do not forget to declare y as static int y;

如果 recyclerview 向下滚动,我想隐藏布局,然后在 recyclerview 向上滚动时使其可见。我想了想,得出了这个逻辑。变量 y 是一个全局静态 int。不要忘记将 y 声明为static int y;

I hope it helps someone :)

我希望它可以帮助某人:)

 mRecyclerView.addOnScrollListener(new EndlessRecyclerOnScrollListener(lLayout) {
           @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
            // super.onScrolled(recyclerView, dx, dy);
                y=dy;
            }

            @Override
            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);
                if(mRecyclerView.SCROLL_STATE_DRAGGING==newState){
                    //fragProductLl.setVisibility(View.GONE);
                }
                if(mRecyclerView.SCROLL_STATE_IDLE==newState){
                   // fragProductLl.setVisibility(View.VISIBLE);
                    if(y<=0){
                        fragProductLl.setVisibility(View.VISIBLE);
                    }
                    else{
                        y=0;
                        fragProductLl.setVisibility(View.GONE);
                    }
                }
            }
        });

回答by silvermouse

Another simple solution that can detect scroll direction with the help of your adapter:

另一个可以在适配器的帮助下检测滚动方向的简单解决方案:

class MyRecyclerViewAdapter extends RecyclerView.Adapter<MyViewHolder> {
    int lastItemPosition = -1;

    @Override
    public void onBindViewHolder(MyViewHolder holder, int position) {
        if (position > lastItemPosition) {
            // Scrolled Down
        }
        else {
            // Scrolled Up
        }
        lastItemPosition = position;
     }
}

^ Helpful when doing item animations upon scrolling.

^ 在滚动时制作项目动画时很有帮助。

PS: This will tell you directions discontinuously until further onBindViewHolder calls.

PS:这会不连续地告诉你方向,直到进一步调用 onBindViewHolder 。

回答by Aleksey Timoshchenko

There is my implementation of CustomRecyclerViewwith all type of scroll listeners

有我对CustomRecyclerView所有类型的滚动侦听器的实现

public class CustomRecyclerView extends RecyclerView
{
private boolean mIsScrolling;
private boolean mIsTouching;
private OnScrollListener mOnScrollListener;
private Runnable mScrollingRunnable;
private int y = 0;

public abstract static class OnScrollListener
{
    void onScrollChanged(CustomRecyclerView RvView, int x, int y, int oldX, int oldY)
    {
        //if you need just override this method
    }

    void onEndScroll(CustomRecyclerView RvView)
    {
        //if you need just override this method
    }

    protected abstract void onGoUp();

    protected abstract void onGoDown();
}

public CustomRecyclerView(final Context context)
{
    super(context);
}

public CustomRecyclerView(final Context context, @Nullable final AttributeSet attrs)
{
    super(context, attrs);
}

public CustomRecyclerView(final Context context, @Nullable final AttributeSet attrs, final int defStyle)
{
    super(context, attrs, defStyle);
}

@Override
public boolean dispatchTouchEvent(MotionEvent iEv)
{
    if (isEnabled())
    {
        processEvent(iEv);
        super.dispatchTouchEvent(iEv);
        return true; //to keep receive event that follow down event
    }

    return super.dispatchTouchEvent(iEv);
}

private void processEvent(final MotionEvent iEv)
{
    switch (iEv.getAction())
    {
        case MotionEvent.ACTION_DOWN:
            y = (int) iEv.getY();
            break;

        case MotionEvent.ACTION_UP:
            y = (int) iEv.getY();

            if (mIsTouching && !mIsScrolling && mOnScrollListener != null)
            {
                mOnScrollListener.onEndScroll(this);
            }

            mIsTouching = false;
            break;
        case MotionEvent.ACTION_MOVE:
            mIsTouching = true;
            mIsScrolling = true;

            int newY = (int) iEv.getY();
            int difY = y - newY;

            int MAX_VALUE = 200;
            int MIN_VALUE = -200;
            if (difY > MAX_VALUE)
            {
                if (mOnScrollListener != null)
                {
                    mOnScrollListener.onGoDown();
                }
                y = newY;
            }
            else if (difY < MIN_VALUE)
            {
                if (mOnScrollListener != null)
                {
                    mOnScrollListener.onGoUp();
                }
                y = newY;
            }

            break;
    }
}

@Override
protected void onScrollChanged(int iX, int iY, int iOldX, int iOldY)
{
    super.onScrollChanged(iX, iY, iOldX, iOldY);

    if (Math.abs(iOldX - iX) > 0)
    {
        if (mScrollingRunnable != null)
        {
            removeCallbacks(mScrollingRunnable);
        }

        mScrollingRunnable = () ->
        {
            if (mIsScrolling && !mIsTouching && mOnScrollListener != null)
            {
                mOnScrollListener.onEndScroll(CustomRecyclerView.this);
            }

            mIsScrolling = false;
            mScrollingRunnable = null;
        };

        postDelayed(mScrollingRunnable, 200);
    }

    if (mOnScrollListener != null)
    {
        mOnScrollListener.onScrollChanged(this, iX, iY, iOldX, iOldY);
    }
}

public void scrollToView(final View iV)
{
    // Get deepChild Offset
    Point childOffset = new Point();
    getDeepChildOffset(CustomRecyclerView.this, iV.getParent(), iV, childOffset);
    // Scroll to child.

    CustomRecyclerView.this.scrollToY(childOffset.y);
}

private void getDeepChildOffset(final ViewGroup mainParent, final ViewParent parent, final View child, final Point accumulatedOffset)
{
    ViewGroup parentGroup = (ViewGroup) parent;
    accumulatedOffset.x += child.getLeft();
    accumulatedOffset.y += child.getTop();
    if (parentGroup.equals(mainParent))
    {
        return;
    }
    getDeepChildOffset(mainParent, parentGroup.getParent(), parentGroup, accumulatedOffset);
}

public void scrollToY(final int iY)
{
    CustomRecyclerView.this.postDelayed(() ->
    {
        int x = 0;
        int y = iY;
        ObjectAnimator xTranslate = ObjectAnimator.ofInt(CustomRecyclerView.this, "scrollX", x);
        ObjectAnimator yTranslate = ObjectAnimator.ofInt(CustomRecyclerView.this, "scrollY", y);

        AnimatorSet animators = new AnimatorSet();
        animators.setDuration(500L);
        animators.playTogether(xTranslate, yTranslate);
        animators.addListener(new Animator.AnimatorListener()
        {

            @Override
            public void onAnimationStart(Animator arg0)
            {
                // noting
            }

            @Override
            public void onAnimationRepeat(Animator arg0)
            {
                // noting
            }

            @Override
            public void onAnimationEnd(Animator arg0)
            {
                // noting
            }

            @Override
            public void onAnimationCancel(Animator arg0)
            {
                // noting
            }
        });
        animators.start();
    }, 300);
}

public void scrollToTop()
{
    scrollToY(0);
}

public void setOnRvScrollListener(OnScrollListener mOnEndScrollListener)
{
    this.mOnScrollListener = mOnEndScrollListener;
}
}

And there is sample of usage

并且有使用示例

private void setRecyclerViewSettings()
{
    mRv.setLayoutManager(new LinearLayoutManager(getActivity()));
    mRv.setOnRvScrollListener(mScrollListener);
}

private CustomRecyclerView.OnScrollListener mScrollListener = new CustomRecyclerView.OnScrollListener()
{
    @Override
    protected void onGoUp()
    {
        AppUtils.hideKeyboard(getContext(), mRvDynamicFormQuestions.getFocusedChild());
    }

    @Override
    protected void onGoDown()
    {
        AppUtils.hideKeyboard(getContext(), mRvDynamicFormQuestions.getFocusedChild());
    }
};