I very recently started using the SnapHelper
provided inside the Support Library v24
in order to have a nice horizontal RecyclerView
much like in the Google Play Store.
My question is simple.
By using a RecyclerView.OnScrollListener
I can be notified when the scroll state is settling (much like with ViewPager.OnPageChangedListener
. This is important because when the scroll is settling, I need to animate the view that will be centered as the default behavior of the LinearSnapHelper
. That animation shows that the focus is brought to the soon-to-be centered item.
For now, I managed to get the view that is centered when the scroll state is idle via the following line:
final int centered = (llm.findLastCompletelyVisibleItemPosition() - llm.findFirstCompletelyVisibleItemPosition()) / 2 + llm.findFirstVisibleItemPosition(); // where llm is my LinearLayoutManager
Problem is, starting the animation when the scroll is completed is weird: I really need to smoothly play the animation as the scroll is settling so that when the scroll is idle, the animation completes as well.
So as you can see, I have hard time finding out which item of my RecyclerView
will be the one centered.
Here are the solutions I tried so far.
I tried using the same calculation when scroll state is set to RecyclerView.SCROLL_STATE_SETTLING
. Unfortunately, calling the findVisiblePosition
methods from the adapter when the scroll isn't idle is a bad idea : depending on the scroll speed, the visible items, when these so-called methods are invoked, might not be exactly the same when the scroll is complete. Indeed it will tell me which items are visible at the time of the call. That makes total sense but I needed to try to find that out...
I tried extending the LinearSnapHelper
so that when onFling(...)
is called I can either use findSnapView(...)
to get the view that will be snapped or use findTargetSnapPosition(...)
hopefully telling me which view is to be centered when the scroll completes ;
I also tried, when scroll state is RecyclerView.SCROLL_STATE_SETTLING
, to use findSnapView(...)
Of all these solutions, none passed multiple tests (trying with different swipe strength & speed). Some got it right on a few occasions but got it wrong in different circumstances therefore rendering the solution unusable.
Having looked inside the LinearSnapHelper
I think I started to understand that, somehow, after a swipe, this class computes the total scroll and snaps views on multiple occasions as long as necessary before the scroll completes (amount of distance to scroll) therefore knowing which view will be the final snapped view ... unless I got it all wrong because snapped is not centered?
Anyway, my main question is: How can I know which item of my RecyclerView
will be centered after a swipe, regardless of speed and strength of said swipe?
RecyclerView is the ViewGroup that contains the views corresponding to your data. It's a view itself, so you add RecyclerView into your layout the way you would add any other UI element. Each individual element in the list is defined by a view holder object.
The RecyclerView class extends the ViewGroup class and implements ScrollingView interface. It is introduced in Marshmallow. It is an advanced version of the ListView with improved performance and other benefits.
In Android, RecyclerView provides an ability to implement the horizontal, vertical and Expandable List. It is mainly used when we have data collections whose elements can change at run time based on user action or any network events. For using this widget we have to specify the Adapter and Layout Manager.
Simple answer: You should use RecyclerView in a situation where you want to show a lot of items, and the number of them is dynamic. ListView should only be used when the number of items is always the same and is limited to the screen size.
Edit:
As a few have pointed out, this is not reliable, particularly when the snap occurs as the result of a slow swipe rather than a fling.
I'd recommend using a RecyclerView.OnScrollListener
, and checking the position once the RecyclerView
has 'settled'. There's a good tutorial on this here
https://medium.com/over-engineering/detecting-snap-changes-with-androids-recyclerview-snaphelper-9e9f5e95c424
Previous answer:
You need to subclass SnapHelper
and override findTargetSnapPosition
. The position calculated by super.findTargetSnapPosition(layoutManager, velocityX, velocityY)
is the position your RecyclerView
is about to snap to.
SnapHelper snapHelper = new LinearSnapHelper() {
@Override
public int findTargetSnapPosition(RecyclerView.LayoutManager layoutManager, int velocityX, int velocityY) {
int snapPosition = super.findTargetSnapPosition(layoutManager, velocityX, velocityY);
// Do something with snapPosition
return snapPosition;
}
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With