web-dev-qa-db-fra.com

Ecouteur UP / DOWN avec défilement RecyclerView

Comment savons-nous si l'utilisateur a fait défiler l'écran vers le bas ou vers le haut dans RecyclerView?

J'ai essayé avec RecyclerView#OnScrollListener, il donne la quantité de défilement vertical et l’état de défilement. Comment pouvons-nous obtenir la dernière position de défilement lorsque vous commencez à faire glisser et la position de défilement lorsque l'état de défilement est inactif.

Merci.

37
Libin

Essayez de cette façon:

private static int firstVisibleInListview;

firstVisibleInListview = yourLayoutManager.findFirstVisibleItemPosition();

Dans votre écouteur de défilement:

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;

}
29
Xcihnegn

La réponse acceptée fonctionne bien, mais @MaciejPigulski a donné une solution plus claire et plus nette dans le commentaire ci-dessous. Je viens de le mettre comme une réponse ici. Voici mon code de travail.

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
        }
    }
});
76
Reaz Murshed

Je voulais cacher une mise en page si la vue recyclée est défilée et la rendre visible si la vue recyclée est défilée. J'ai réfléchi et j'ai proposé cette logique. La variable y est un entier statique global. N'oubliez pas de déclarer y comme static int y;

J'espère que ça aide quelqu'un :)

 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);
                    }
                }
            }
        });
10
Shahid Sarwar

Une autre solution simple permettant de détecter le sens de défilement à l’aide de votre adaptateur:

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;
     }
}

^ Utile pour les animations d’éléments lors du défilement.

PS: Cela vous indiquera les directions de manière discontinue jusqu'à ce que d'autres appels onBindViewHolder soient effectués.

2
Himanshu Likhyani

Il y a mon implémentation de CustomRecyclerView avec tous les types d'écoute de défilement

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;
}
}

Et il y a un exemple d'utilisation

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());
    }
};
1