Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android - Get current position from recyclerview with listener when position changed

I'm working with recyclerview with snaphelper. this is my recyclerview:

    final LinearLayoutManager lm = new LinearLayoutManager(getContext(), 
    LinearLayoutManager.HORIZONTAL, false);

    recyclerview.setLayoutManager(lm);

    final PagerSnapHelper snapHelper = new PagerSnapHelper();
    snapHelper.attachToRecyclerView(recyclerview);

when user scroll to another cell i need to do something with the new cell position.

this is what i do to get the position:

        recyclerview.addOnScrollListener(new RecyclerView.OnScrollListener() {
        @Override
        public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
            if (newState != RecyclerView.SCROLL_STATE_IDLE) {
                return;
            }
            if recyclerview == null) {
                return;
            }
             //recyclerview.clearOnChildAttachStateChangeListeners();
            int firstVisible = ((LinearLayoutManager) viewerRv.getLayoutManager()).findFirstCompletelyVisibleItemPosition();
            if (firstVisible == RecyclerView.NO_POSITION) {
                return;
            }

          doSomething(firstVisible);
       }

the problem is the firstVisible var not always give me the right position for example when i scroll from position 0 to 9 this can be the output: 0,1,2,3,4,4,5,9

there is another way to get the right current position?

what are the best practices for that?

like image 410
Yoni Avatar asked Oct 09 '17 19:10

Yoni


2 Answers

this my solution :

        recyclerview.addOnScrollListener(new RecyclerView.OnScrollListener() {
        @Override
        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
            super.onScrolled(recyclerView, dx, dy);
            final int offset = topRv.computeHorizontalScrollOffset();
            if (offset % myCellWidth == 0) {
                final int position = offset / myCellWidth ;
            }
        }
    });

this solution gives me the current position constantly

like image 151
Yoni Avatar answered Oct 13 '22 16:10

Yoni


The documentation for onScrollStateChanged(int state) explain:

  • SCROLL_STATE_IDLE: No scrolling is done.

  • SCROLL_STATE_DRAGGING: The user is dragging his finger on the screen (or it is being done programatically.

  • SCROLL_STATE_SETTLING: User has lifted his finger, and the animation is now slowing down.

You get position when state is SCROLL_STATE_DRAGGING or SCROLL_STATE_SETTLING, obviously this return all of positions that recycler view has scrolled. If you want to get the current position, you should get when the recyclerview stops (newState = SCROLL_STATE_IDLE)

You could use code similar to this for control start and ends of scroll:

boolean hasStarted = (state == SCROLL_STATE_DRAGGING);
boolean hasEnded = (state == SCROLL_STATE_IDLE);

So the final code could be some like this:

     //Initialize this variable on class that initialize recyclerview
     private boolean hasStarted;

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

      //Scroll is not start and user is dragging his finger  
      if(!hasStarted && newState == SCROLL_STATE_DRAGGING){
          hasStarted = true;
      }

      //If scroll starts and it finish
      if(hasStarted && newState == SCROLL_STATE_IDLE){
          //Restart variable for next iteration
          hasStarted = false;
          //Do something
          doSomething(firstVisible);
      }
   }
like image 21
Suaro Avatar answered Oct 13 '22 17:10

Suaro