When the dragging of Outer UIScrollView is ended, and it continues decelerating, we want to transfer that decelerating to the Nested UIScrollView to make users feel they’re only one UIScrollView
Decelerator
I was inspired by this nice article about Deceleration mechanics of UIScrollView
So this article will show you how to apply it to Outer/Nested UIScrollView 👆
I create a class called ScrollingDecelerator, and it will manage the transfering decelerating between outer and nested UIScrollView.
How to use
Downward Decelerating: Outer UIScrollView ==> Nested UIScrollView
For the Outer UIScrollView:
var outerDeceleration: ScrollingDeceleration?
func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
outerDeceleration = ScrollingDeceleration(velocity: velocity, decelerationRate: scrollView.decelerationRate)
}
func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
outerDeceleration = nil
}
func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
outerDeceleration = nil
}
In some place where you need to pass the outerDeceleration into the Nested UIScrollView
Continue downward decelerating for the Nested UIScrollView:
let nestedScrollingDecelerator = ScrollingDecelerator(scrollView: nestedScrollView)
func scrollViewDidScroll(_ scrollView: UIScrollView) {
nestedScrollingDecelerator.invalidateIfNeeded()
}
When the Nested UIScrollView got the outerDeceleration, we can continue the downward decelerating by:
nestedScrollingDecelerator.decelerate(by: outerDeceleration)
Upward Decelerating: Outer UIScrollView <== Nested UIScrollView
For the Nested UIScrollView: We constructed the deceleration, and send it out!
var nestedDeceleration: ScrollingDeceleration?
func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
nestedDeceleration = ScrollingDeceleration(velocity: velocity, decelerationRate: scrollView.decelerationRate)
}
func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
nestedDeceleration = nil
}
func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
nestedDeceleration = nil
}
And pass the nestedDeceleration out to the Outer UIScrollView
And for the Outer UIScrollView:
let outerScrollingDecelerator = ScrollingDecelerator(scrollView: nestedScrollView)
func scrollViewDidScroll(_ scrollView: UIScrollView) {
outerScrollingDecelerator.invalidateIfNeeded()
}
When the Outer UIScrollView got the nestedDeceleration, we can continue the upward decelerating by:
souterScrollingDecelerator.decelerate(by: nestedDeceleration)