Optimizing Fast and Precise Scrolling in Android RecyclerView
By preloading off-screen items, applying a short non-animated jump for large distances, and then using a customized smooth-scroll with precise offset correction, the Android RecyclerView achieves fast, accurate scrolling without white-screen flashes or abrupt stops, greatly improving navigation of long, dynamically-sized lists.
After the new result page was launched, Taobao Photo’s list changed from a short list to a multi‑floor long list. When a user clicks a floor tab, the list must scroll to the corresponding position. Because the product blocks are loaded lazily and their heights are dynamic, Android’s native scrollTo can be slow and inaccurate.
The two main pain points are:
How to scroll quickly to a target position.
How to scroll precisely to a target position.
Solution 1.0 : Override LinearSmoothScroller.calculateTimeForScrolling to reduce the scrolling time when the distance exceeds one screen. This speeds up the animation but introduces inconsistent speed and a white‑screen issue caused by ViewHolder reuse.
Solution 2.0 : Limit the scrolling time to a fixed duration (e.g., 300 ms) and then perform an instant, non‑animated jump. The scroll feels smoother but the final stop is still abrupt.
Solution 3.0 : Combine both ideas – if the distance is large, first perform a non‑animated jump to an offset (e.g., 1.5 screens), then use the native smooth‑scroll for the remaining distance. This avoids both the white‑screen and the harsh stop.
Implementation details:
Check whether the target view is already on screen using StaggeredGridLayoutManager.findViewByPosition .
If the target is off‑screen, preload views with layoutManager.scrollToPositionWithOffset(targetPosition, offset) , where offset is a multiple of the screen height.
After layout finishes, compute the exact dy with a custom FakeScroller and trigger a smooth scroll.
Listen to onScrolled , onScrollStateChanged , and onGlobalLayout to correct the final position when dynamic heights change.
Key code snippets:
/** Calculates the time it should take to scroll the given distance (in pixels) */
protected int calculateTimeForScrolling(int dx) {
return (int) Math.ceil(Math.abs(dx) * getSpeedPerPixel());
} @Override
protected int calculateTimeForScrolling(int dx) {
if (Math.abs(dx) > recyclerView.getMeasuredHeight()) {
return (int) (super.calculateTimeForScrolling(dx) * 0.2f);
} else {
return super.calculateTimeForScrolling(dx);
}
} StaggeredGridLayoutManager manager = (StaggeredGridLayoutManager) recyclerView.getLayoutManager();
View targetView = manager.findViewByPosition(targetPosition);
if (targetView != null) {
smoothScroll(targetPosition, offset);
return;
} layoutManager.scrollToPositionWithOffset(targetPosition, x); // x = 1.5 * screen height public void onLayoutCompleted(RecyclerView.State state) {
// trigger smooth scroll if needed
}The final approach achieves both fast and precise scrolling without the white‑screen or abrupt‑stop problems, providing a smoother user experience for long, dynamic lists.
Conclusion: By analyzing RecyclerView internals and combining a non‑animated jump with native smooth scrolling, list navigation becomes faster, more accurate, and more reliable.
DaTaobao Tech
Official account of DaTaobao Technology
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.