Android - Recyclerview customizing smoothscroller
First, this is not a full comprehensive in-depth guide for the
SmoothScroller
, but I hope this gives you a jumpstart on where you can begin customizing because I could not find any clear tutorials on this topic.
What is a
SmoothScroller
you ask? A SmoothScroller
is exactly as it seems. It’s a Class
that helps a View
scroll to an item’s position smoothly to create a seamless transition as opposed to snapping to it abruptly. In this example I will be using its child Class
LinearSmoothScroller
with the RecyclerView
.
We all know that to initialize a
RecylerView
we need to set a LayoutManager
like so:
1
| mRecyclerView.setLayoutManager(mLinearLayoutManager); |
or else an error will occur during run-time. Well, the
LayoutManager
is in charge of the smooth scrolling! Therefore, in order to customize the SmoothScroller
we need to create our own custom LayoutManager
first.1. Setup
I will be customizing the
LinearLayoutManager
.
1
2
3
4
5
6
| public class MyCustomLayoutManager extends LinearLayoutManager { public MyCustomLayoutManager(Context context) { super (context); } } |
After this step we want to override this method (taken from Google Docs):
1
2
3
4
5
6
7
8
9
| public void smoothScrollToPosition (RecyclerView recyclerView, RecyclerView.State state, int position) /*Smooth scroll to the specified adapter position. To support smooth scrolling, 1. Override this method, 2. Create your RecyclerView.SmoothScroller instance 3. Call startSmoothScroll(SmoothScroller).*/ |
The docs give us all the directions we need to support smooth scrolling!… or does it?
Lets override this method first, implementing what the docs has told us to do. After doing so, our custom
Lets override this method first, implementing what the docs has told us to do. After doing so, our custom
LayoutManager
now looks like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
| public class MyCustomLayoutManager extends LinearLayoutManager { //We need mContext to create our LinearSmoothScroller private Context mContext; public MyCustomLayoutManager(Context context) { super (context); mContext = context; } //Override this method? Check. @Override public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) { //Create your RecyclerView.SmoothScroller instance? Check. LinearSmoothScroller smoothScroller = new LinearSmoothScroller(mContext) { //Automatically implements this method on instantiation. @Override public PointF computeScrollVectorForPosition ( int targetPosition) { return null ; } }; //Docs do not tell us anything about this, //but we need to set the position we want to scroll to. smoothScroller.setTargetPosition(position); //Call startSmoothScroll(SmoothScroller)? Check. startSmoothScroll(smoothScroller); } } |
2. Customizing Direction to Look for the List Item
You may be wondering what does
computeScrollVectorForPosition(int targetPosition)
do? Well, in the Google Docs the documentation is blank.. BLANK! C’mon Google, I am disappoint. Thankfully you have me. I did some testing and scoured the source code for information and this is what I came up with.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| LinearSmoothScroller smoothScroller = new LinearSmoothScroller(mContext) { //This controls the direction in which smoothScroll looks for your //list item @Override public PointF computeScrollVectorForPosition( int targetPosition) { //What is PointF? A class that just holds two float coordinates. //Accepts a (x , y) //for y: use -1 for up direction, 1 for down direction. //for x (did not test): use -1 for left direction, 1 for right //direction. //We let our custom LinearLayoutManager calculate PointF for us return MyCustomLayoutManager. this .computeScrollVectorForPosition (targetPosition); } }; |
To clarify, what
computeScrollVectorForPosition(...)
does is that if my screen was in the middle of the list (item #50) and I wanted to go to item #100, if I returned PointF(0, 1)
, it will scroll downwards til it finds item #100. If it was PointF(0, -1)
, it would scroll up to find item #100, which will make it scroll all the way to the top since it won’t find item #100 obviously.
Recommended: Just let
SmoothScroller
automatically calculate the direction to look for the list item by returning :MyCustomLayoutManager.this.computeScrollVectorForPosition(targetPosition);
(lines 14, 15)3. Customizing Scrolling Speed
Next, how do we customize scrolling speed?
This is probably the number one reason why anyone would want to create a custom
This is probably the number one reason why anyone would want to create a custom
SmoothScroller
in the first place. All you need to do is override this method in yourLinearSmoothScroller
instance:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| //Make an instance variable at the top of you custom LayoutManager private static final float MILLISECONDS_PER_INCH = 50f; . . . LinearSmoothScroller smoothScroller = new LinearSmoothScroller(mContext) { . . . //The holy grail of smooth scrolling //returns the milliseconds it takes to scroll one pixel. @Override protected float calculateSpeedPerPixel (DisplayMetrics displayMetrics) { return MILLISECONDS_PER_INCH / displayMetrics.densityDpi; } }; |
calculateSpeedPerPixel(DisplayMetrics displayMetrics)
allows you to adjust how fast you want the SmoothScroller
to scroll over a pixel on your screen!
Some devices have
480 pixels
in an inch and some have 240 pixels
in an inch. More pixels means that it will take longer to scroll one inch as compared to a lower dpi device. Therefore, we need to find an equation that can solve that problem:MILLISECONDS_PER_INCH
is how fast we want it to scroll one inch. We divide it bydisplayMetrics.densityDpi
because we want that speed to look consistent through different devices with different pixel densities. Higher dpi devices will have to scroll through pixels at a faster rate than that of a lower dpi device to keep up. I used 50 ms/inch but you can do whatever you like.4. Finally
In the end your custom
LinearLayoutManager
should look like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
| public class MyCustomLayoutManager extends LinearLayoutManager { private static final float MILLISECONDS_PER_INCH = 50f; private Context mContext; public MyCustomLayoutManager(Context context) { super (context); mContext = context; } @Override public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, final int position) { LinearSmoothScroller smoothScroller = new LinearSmoothScroller(mContext) { //This controls the direction in which smoothScroll looks //for your view @Override public PointF computeScrollVectorForPosition ( int targetPosition) { return MyCustomLayoutManager. this .computeScrollVectorForPosition(targetPosition); } //This returns the milliseconds it takes to //scroll one pixel. @Override protected float calculateSpeedPerPixel (DisplayMetrics displayMetrics) { return MILLISECONDS_PER_INCH/displayMetrics.densityDpi; } }; smoothScroller.setTargetPosition(position); startSmoothScroll(smoothScroller); } } |
To wrap it all up, you can now set
MyCustomLayoutManager
to your RecyclerView
and callsmoothScrollToPosition(position)
. It should now scroll smooth like butter.
1
2
3
| mLayoutManager = new MyCustomLayoutManager(getActivity()); mRecyclerView.setLayoutManager(mLayoutManager); mRecyclerView.smoothScrollToPosition(position); |
Hopefully my directions were helpful and you weren’t too overwhelmed. To find out what other methods you can overwrite to customize the
LinearSmoothScroller
even further please visit:https://developer.android.com/reference/android/support/v7/widget/LinearSmoothScroller.html
Thanks and remember coding can get very complex. Hang in there!
from : https://mcochin.wordpress.com
No comments: