Siavash
Siavash

Reputation: 7853

How to programmatically snap to position on Recycler view with LinearSnapHelper

I have implemented a horizontal recyclerView with LinearSnapHelper, to implement a UI input that selects a particular configuration. Kinda like the old school number picker/selector or spinner. The item in the center is the selected position.

it works fine and all, but here's the problem. On initial start up, I need to programmatically set the position of the recycler view such that the selected item (the index of which was loaded from disk) is position in the center.

.scrollToPosition() wont work becuase it places the selected item in the begining.

now I know I can do all the math and calculate the x coordinate and manually set it, but thats a lot of redundant work because LinearSnapHelper is already doing this, and I feel like there should be a way to just reuse that logic, but with actually initiating a fling.

I need something like LinearSnapHelper.snapToPosition()

Upvotes: 20

Views: 12963

Answers (4)

Sanjay S Gangwar
Sanjay S Gangwar

Reputation: 1

greetRecycler.scrollToPosition(targetPosition)


greetRecycler.post {
    val view = layoutManager.findViewByPosition(targetPosition)
    if (view == null) {
      Log.e("SANJAY", "Cant find target View for initial Snap")
      return@post
    }

    val snapDistance = snapHelper.calculateDistanceToFinalSnap(layoutManager, view)
    snapDistance?.let {
      if (it[0] != 0 || it[1] != 0) {
        greetRecycler.scrollBy(it[0], it[1])
      }
    }
  }

Upvotes: 0

donaldTheDuck
donaldTheDuck

Reputation: 397

More general solution:

  1. First scroll RecyclerView to make target item visible.
  2. Than, take the object of target View and use SnapHelper to determine distance for the final snap.
  3. Finally scroll to target position.

NOTE: This works only because programmatically you are scrolling at the exact position & covering the missing distance by exact value using scrollBy instead of doing smooth scrolling

Code snippet:

mRecyclerView.scrollToPosition(selectedPosition);
mRecyclerView.post(() -> {
        View view = mLayoutManager.findViewByPosition(selectedPosition);
        if (view == null) {
            Log.e(WingPickerView.class.getSimpleName(), "Cant find target View for initial Snap");
            return;
        }

        int[] snapDistance = mSnapHelper.calculateDistanceToFinalSnap(mLayoutManager, view);
        if (snapDistance[0] != 0 || snapDistance[1] != 0) {
            mRecyclerView.scrollBy(snapDistance[0], snapDistance[1]);
        }
    }
});

Upvotes: 38

user2486946
user2486946

Reputation: 37

I have a recyclerView which I have added padding at the left and right with dummy views in the adapter. So that the first "actual" item can be snapped to.

I couldn't get smoothScrollToPosition(0) to work though for the initial snap. I used the following

recycler.scrollBy(snapHelper.calculateDistanceToFinalSnap(binding.recycler.getLayoutManager(), recycler.getChildAt(1))[0], 0);

Isn't the nicest looking way, but seems to work!

Upvotes: -2

Miro
Miro

Reputation: 89

Try calling smoothScrollToPosition on the RecyclerView object, and passing the position index (int)

mRecyclerView.smoothScrollToPosition(position);

Worked for me with a LinearLayoutManager and LinearSnapHelper. It animates the initial scroll, but at least snaps the item in position.

This is my first post on the stack, hope it helps :)

Upvotes: 7

Related Questions