Android RecyclerView(GridLayoutManager)smoothScrollTo()滚动速度调整问题
I’ve run into this exact issue before—using smoothScrollToPosition() with GridLayoutManager often skips the smooth animation and jumps straight to the last item, which is super frustrating. The solutions you found for LinearLayoutManager don’t translate directly, but here are two tested fixes that work for Grid layouts:
Method 1: Custom LinearSmoothScroller
The default smooth scroller for GridLayoutManager doesn’t handle direction or speed correctly. By creating a custom scroller, you can enforce proper smooth scrolling behavior:
import android.content.Context import android.graphics.PointF import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.LinearSmoothScroller class GridSmoothScroller(context: Context) : LinearSmoothScroller(context) { override fun computeScrollVectorForPosition(targetPosition: Int): PointF? { val layoutManager = layoutManager as? GridLayoutManager ?: return super.computeScrollVectorForPosition(targetPosition) val firstVisibleItem = layoutManager.findFirstVisibleItemPosition() // Determine scroll direction (down if target is below first visible item) val scrollDirection = if (targetPosition > firstVisibleItem) 1 else -1 return PointF(0f, scrollDirection.toFloat()) } override fun calculateSpeedPerPixel(displayMetrics: DisplayMetrics?): Float { // Adjust this value to control scroll speed: higher = slower return 200f / (displayMetrics?.densityDpi ?: 160) } override fun getVerticalSnapPreference(): Int { // Snap to the bottom of the target item for consistent behavior return SNAP_TO_END } }
To use this scroller instead of the default:
val gridLayoutManager = recyclerView.layoutManager as GridLayoutManager val smoothScroller = GridSmoothScroller(recyclerView.context) smoothScroller.targetPosition = adapter.itemCount - 1 gridLayoutManager.startSmoothScroll(smoothScroller)
This method overrides how the scroller calculates direction and speed, ensuring smooth vertical scrolling regardless of grid column count.
Method 2: Manual Smooth Scroll with ValueAnimator
If you need more control over the animation (like custom duration), you can manually animate the scroll using ValueAnimator:
import android.animation.ValueAnimator import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.RecyclerView fun smoothScrollToBottom(recyclerView: RecyclerView, layoutManager: GridLayoutManager) { val totalItems = recyclerView.adapter?.itemCount ?: 0 if (totalItems <= 0) return val targetPosition = totalItems - 1 val lastVisiblePosition = layoutManager.findLastVisibleItemPosition() // If already near the bottom, use default smooth scroll if (lastVisiblePosition >= targetPosition - 3) { recyclerView.smoothScrollToPosition(targetPosition) return } // Check if target view is already laid out val targetView = layoutManager.findViewByPosition(targetPosition) targetView?.let { val totalScrollDistance = it.bottom - recyclerView.height + recyclerView.paddingBottom ValueAnimator.ofInt(0, totalScrollDistance).apply { duration = 800 // Adjust animation length here (ms) addUpdateListener { animator -> val currentScroll = animator.animatedValue as Int recyclerView.scrollBy(0, currentScroll - recyclerView.scrollY) } start() } } ?: run { // Target view isn't loaded yet—scroll close first, then smooth scroll recyclerView.scrollToPosition(targetPosition - 5) recyclerView.post { smoothScrollToBottom(recyclerView, layoutManager) } } }
Call this function whenever you need to scroll to the bottom:
smoothScrollToBottom(recyclerView, gridLayoutManager)
This approach calculates the exact distance needed to scroll and animates it incrementally, avoiding the jumpy behavior of the default method.
Both methods work reliably for GridLayoutManager—pick the one that fits your use case best!
内容的提问来源于stack exchange,提问作者Mo Dev

