Fix an issue where a tracking scroll content stops and the panel doesn't move (#530)

This commit is contained in:
Shin Yamamoto
2023-07-19 16:18:41 +09:00
committed by GitHub
parent a917d6a626
commit 6611ec83a2
+23 -16
View File
@@ -66,6 +66,7 @@ class Core: NSObject, UIGestureRecognizerDelegate {
private var stopScrollDeceleration: Bool = false
private var scrollBounce = false
private var scrollIndictorVisible = false
private var scrollBounceThreshold: CGFloat = -30.0
// MARK: - Interface
@@ -337,7 +338,10 @@ class Core: NSObject, UIGestureRecognizerDelegate {
if surfaceView.grabberAreaContains(gestureRecognizer.location(in: surfaceView)) {
return false
}
return allowScrollPanGesture(for: scrollView)
guard state == layoutAdapter.mostExpandedState else { return false }
// The condition where offset > 0 must not be included here. Because it will stop recognizing
// the panel pan gesture if a user starts scrolling content from an offset greater than 0.
return allowScrollPanGesture(of: scrollView) { offset in offset <= scrollBounceThreshold }
default:
return false
}
@@ -456,21 +460,24 @@ class Core: NSObject, UIGestureRecognizerDelegate {
}
} else {
if state == layoutAdapter.mostExpandedState {
let allowScroll = allowScrollPanGesture(of: scrollView) { offset in
offset <= scrollBounceThreshold || 0 < offset
}
switch layoutAdapter.position {
case .top, .left:
if velocity < 0, !allowScrollPanGesture(for: scrollView) {
if velocity < 0, !allowScroll {
lockScrollView(strict: true)
}
if velocity > 0, allowScrollPanGesture(for: scrollView) {
if velocity > 0, allowScroll {
unlockScrollView()
}
case .bottom, .right:
// Hide a scroll indicator just before starting an interaction by swiping a panel down.
if velocity > 0, !allowScrollPanGesture(for: scrollView) {
if velocity > 0, !allowScroll {
lockScrollView(strict: true)
}
// Show a scroll indicator when an animation is interrupted at the top and content is scrolled up
if velocity < 0, allowScrollPanGesture(for: scrollView) {
if velocity < 0, allowScroll {
unlockScrollView()
}
}
@@ -803,13 +810,14 @@ class Core: NSObject, UIGestureRecognizerDelegate {
initialScrollOffset = scrollView.contentOffset
} else {
let pinningOffset = contentOffsetForPinning(of: scrollView)
// `scrollView.contentOffset` can be a value in [-30, 0) at this time by `allowScrollPanGesture(for:)`.
// Therefore the initial scroll offset must be reset to the pinning offset. Otherwise, the following
// `Fit the surface bounds` logic don't working and also the scroll content offset can be invalid.
// `initialScrollOffset` must be reset to the pinning offset because the value of `scrollView.contentOffset`,
// for instance, is a value in [-30, 0) on a bottom positioned panel with `allowScrollPanGesture(of:condition:)`.
// If it's not reset, the following logic to shift the surface frame will not work and then the scroll
// content offset will become an unexpected value.
initialScrollOffset = pinningOffset
// Fit the surface bounds to a scroll offset content by startInteraction(at:offset:)
// Shift the surface frame to negate the scroll content offset at startInteraction(at:offset:)
let offsetDiff = scrollView.contentOffset - pinningOffset
switch layoutAdapter.position {
case .top, .left:
@@ -1103,16 +1111,15 @@ class Core: NSObject, UIGestureRecognizerDelegate {
}
}
private func allowScrollPanGesture(for scrollView: UIScrollView) -> Bool {
guard state == layoutAdapter.mostExpandedState else { return false }
var offsetY: CGFloat = 0
private func allowScrollPanGesture(of scrollView: UIScrollView, condition: (_ offset: CGFloat) -> Bool) -> Bool {
var offset: CGFloat = 0
switch layoutAdapter.position {
case .top, .left:
offsetY = value(of: scrollView.fp_contentOffsetMax - scrollView.contentOffset)
offset = value(of: scrollView.fp_contentOffsetMax - scrollView.contentOffset)
case .bottom, .right:
offsetY = value(of: scrollView.contentOffset - contentOffsetForPinning(of: scrollView))
offset = value(of: scrollView.contentOffset - contentOffsetForPinning(of: scrollView))
}
return offsetY <= -30.0 || offsetY > 0
return condition(offset)
}
// MARK: - UIPanGestureRecognizer Intermediation