I want to implement the iOS-like bounce overscroll effect in my app.
I came across this link which suggests creating a custom ScrollView
. But the problem is
Thanks to Xaver Kapeller, I have written my solution with overriding fling and little additions, using kotlin and androidx
Add coordinator dependency
implementation "androidx.coordinatorlayout:coordinatorlayout:1.1.0"
Create a new class that extends CoordinatorLayout.Behavior
import android.content.Context
import android.util.AttributeSet
import android.view.View
import android.view.ViewGroup
import android.view.animation.AccelerateDecelerateInterpolator
import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.core.view.ViewCompat
class OverScrollBehavior(context: Context, attributeSet: AttributeSet)
: CoordinatorLayout.Behavior() {
companion object {
private const val OVER_SCROLL_AREA = 4
}
private var overScrollY = 0
override fun onStartNestedScroll(
coordinatorLayout: CoordinatorLayout,
child: View,
directTargetChild: View,
target: View,
axes: Int,
type: Int
): Boolean {
overScrollY = 0
return true
}
override fun onNestedScroll(
coordinatorLayout: CoordinatorLayout,
child: View,
target: View,
dxConsumed: Int,
dyConsumed: Int,
dxUnconsumed: Int,
dyUnconsumed: Int,
type: Int,
consumed: IntArray
) {
if (dyUnconsumed == 0) {
return
}
overScrollY -= (dyUnconsumed/OVER_SCROLL_AREA)
val group = target as ViewGroup
val count = group.childCount
for (i in 0 until count) {
val view = group.getChildAt(i)
view.translationY = overScrollY.toFloat()
}
}
override fun onStopNestedScroll(
coordinatorLayout: CoordinatorLayout,
child: View,
target: View,
type: Int
) {
// Smooth animate to 0 when the user stops scrolling
moveToDefPosition(target)
}
override fun onNestedPreFling(
coordinatorLayout: CoordinatorLayout,
child: View,
target: View,
velocityX: Float,
velocityY: Float
): Boolean {
// Scroll view by inertia when current position equals to 0
if (overScrollY == 0) {
return false
}
// Smooth animate to 0 when user fling view
moveToDefPosition(target)
return true
}
private fun moveToDefPosition(target: View) {
val group = target as ViewGroup
val count = group.childCount
for (i in 0 until count) {
val view = group.getChildAt(i)
ViewCompat.animate(view)
.translationY(0f)
.setInterpolator(AccelerateDecelerateInterpolator())
.start()
}
}
}
Create XML file with CoordinatorLayout and NestedScrollView
And don't forget to add
app:layout_behavior=".OverScrollBehavior" // Or your file name
field to your NestedScrollView XML markup