An in-depth look at SnapHelper: New tools in RecyclerView part-2

Samvid Mistry
CodeWord
Published in
4 min readDec 13, 2016

SnapHelper helps in snapping the views to boundries of the RecyclerView, that’s what I thought it was… until I went through the source code. Now I believe SnapHelper can be used to snap the child to any imaginary point or any pixel on the screen.

If you have not read the first part of this series of articles, I highly encourage you to read it here, https://medium.com/codeword/new-tools-in-recyclerview-diffutil-snaphelper-and-more-part-1-e501cbccc9aa#.l1yc198p3. This article takes a look at how you can use ItemDecorations to provide certain things such as margins and borders around RecyclerView items. Now, I won’t be showing much of the source code here, because you can already look up the source code, what I’ll do is, I’ll explain the logic it follows in plain simple english language so you can have an abstract idea about how the things are working under the hood rather than bothering yourself with the source code.

Let’s get into the SnapHelper stuff now. It is really intuitive, but unfortunately it did not come to my mind that SnapHelper actually extends RecyclerView.OnFlingListener. It is obvious that you want to settle some item at some place after you fling or scroll it. It is an abstract class, but it does a good job at handling much of the boilerplate code for snapping. Now even if the SnapHelper is a fling listener, it also handles scrolls also, which is also intuitive. Let’s take a look at a simple diagram which shows an abstract flow of the functions involved in snapping process.

Basic flow for snapping a view

onFling: This method does nothing much in case of snapping. It basically checks for a few constraints to make sure that we are flinging and then hands over the control to the method snapFromFling.

snapFromFling: This method settles or snaps the view to the required position and is the ultimate method in case of flinging. At the end of this method, the view is supposed to be snapped at it supposed position. But it calls many complex methods in process of doing so, first of them is createSnapScroller.

createSnapScroller: This method basically returns an instance of LinearSmoothScroller, it is an implementation of SmoothScroller which is the class responsible for programatically scrolling the RecyclerView. It overrides 2 methods in the class. The more interesting one is onTargetFound. This method is called when the final view upto which the scroller is supposed to scroll is laid out on the screen. Now this method in the SnapHelper class calls an abstract method calculateDistanceToFinalSnap. This method is supposed to return the distance, in pixels, upto which RecyclerView is supposed to be scrolled. It is an important method to look for, for subclasses. After getting the instance of SmoothScroller, findTargetSnapPosition is called.

findTargetSnapPosition: This is also an abstract method which is supposed to return the position upto which the RecyclerView is supposed to be scrolled.

smoothScroll: the target position provided by findTargetSnapPosition is then fed into SmoothScroller and then SmoothScroller is then given to LayoutManager to smooth scroll to that position.

Snapping while scrolling is similar and quite less complex as compared to the flow of the fling. You can look it up by yourself as I have already explained the hard bit.

Now what the SDK provides us as implementation of SnapHelper is a single class named LinearSnapHelper. I thought the LinearSnapHelper would be providing the functionality to snap views to either of the sides of the RecyclerView, but as the source code is written, it actually snaps the view which is nearest to the center, to center.

Now let’s discuss how LinearSnapHelper has implemented the abstract methods of SnapHelper.

findSnapView: This is the most simplest method of all implemented methods. It just checks if the RecyclerView is scrolling vertically or horizontally and finds a child in the center of the screen according to the orientation.

findTargetSnapPosition: This method does a lot of heavy lifting in the snapping when flinging. The overall flow of this method is, first, according to the velocity of the touch, it calculates the the number of children it is going to fling over and on which child is it going to stop. The value is just an estimated one here, not striving for the perfect value because fling is naturally uncertain.

calculateDistanceToFinalSnap: This method works similar to findSnapView, in the sense that it also finds the center view in the current RecyclerView layout, the difference is that this method actually returns the distance in pixels to scroll the RecyclerView upto.

Now the implementation is really really small and easy. It is just a single line, if you will.

new LinearSnapHelper().attachToRecyclerView(recyclerViewObject);

So this is how the SnapHelper works internally and how LinearSnapHelper works against my intuitive idea of how it would work. If you want a SnapHelper that snaps to either edge of the RecyclerView, I suggest you to check out https://github.com/DevExchanges/SnappingRecyclerview. In the next article, we may see another component in depth.

--

--