From 0df58af5628bbe684414cea5df68cc1f36f82269 Mon Sep 17 00:00:00 2001 From: Meenbeese Date: Wed, 7 Aug 2024 16:48:50 -0400 Subject: [PATCH] Implement faster quadratic speed scrolling --- .../droidify/ui/appList/AppListFragment.kt | 7 ++- .../java/com/looker/core/common/Scroller.kt | 54 +++++++++++++++++++ 2 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 core/common/src/main/java/com/looker/core/common/Scroller.kt diff --git a/app/src/main/kotlin/com/looker/droidify/ui/appList/AppListFragment.kt b/app/src/main/kotlin/com/looker/droidify/ui/appList/AppListFragment.kt index 00675b86..cb658649 100644 --- a/app/src/main/kotlin/com/looker/droidify/ui/appList/AppListFragment.kt +++ b/app/src/main/kotlin/com/looker/droidify/ui/appList/AppListFragment.kt @@ -14,6 +14,7 @@ import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView +import com.looker.core.common.Scroller import com.looker.core.common.R as CommonR import com.looker.core.common.R.string as stringRes import com.looker.core.common.extension.dp @@ -104,7 +105,11 @@ class AppListFragment() : Fragment(), CursorOwner.Callback { } else { text = "" setIconResource(CommonR.drawable.arrow_up) - setOnClickListener { recyclerView.smoothScrollToPosition(0) } + setOnClickListener { + val scroller = Scroller(requireContext()) + scroller.targetPosition = 0 + recyclerView.layoutManager?.startSmoothScroll(scroller) + } alpha = 0f isVisible = true systemBarsMargin(16.dp) diff --git a/core/common/src/main/java/com/looker/core/common/Scroller.kt b/core/common/src/main/java/com/looker/core/common/Scroller.kt new file mode 100644 index 00000000..22abb836 --- /dev/null +++ b/core/common/src/main/java/com/looker/core/common/Scroller.kt @@ -0,0 +1,54 @@ +package com.looker.core.common + +import android.content.Context +import android.util.DisplayMetrics +import android.view.View +import androidx.recyclerview.widget.LinearSmoothScroller +import androidx.recyclerview.widget.RecyclerView +import kotlin.math.abs + +/** + * A custom LinearSmoothScroller that increases the scrolling speed quadratically + * based on the distance already scrolled. + * + * @param context The context used to access resources. + */ +class Scroller(context: Context) : LinearSmoothScroller(context) { + private var distanceScrolled = 0 + + /** + * Calculates the speed per pixel based on the display metrics and the distance + * already scrolled. The speed increases quadratically over time. + * + * @param displayMetrics The display metrics used to calculate the speed. + * @return The speed per pixel. + */ + override fun calculateSpeedPerPixel(displayMetrics: DisplayMetrics): Float { + return (10f / displayMetrics.densityDpi) / (1 + 0.001f * distanceScrolled * distanceScrolled) + } + + /** + * Called when the target view is found. Resets the distance scrolled. + * + * @param targetView The target view. + * @param state The current state of RecyclerView. + * @param action The action to be performed. + */ + override fun onTargetFound(targetView: View, state: RecyclerView.State, action: Action) { + super.onTargetFound(targetView, state, action) + distanceScrolled = 0 + } + + /** + * Called when seeking the target step. Accumulates the distance scrolled. + * + * @param dx The amount of horizontal scroll. + * @param dy The amount of vertical scroll. + * @param state The current state of RecyclerView. + * @param action The action to be performed. + */ + override fun onSeekTargetStep(dx: Int, dy: Int, state: RecyclerView.State, action: Action) { + super.onSeekTargetStep(dx, dy, state, action) + distanceScrolled += abs(dy) + } +}