Skip to content

Commit

Permalink
Fix an issue where a tracking scroll content stops and the panel does…
Browse files Browse the repository at this point in the history
…n't move

Resolve #530
  • Loading branch information
scenee committed Jul 12, 2023
1 parent a917d6a commit 3c6ee6f
Showing 1 changed file with 23 additions and 16 deletions.
39 changes: 23 additions & 16 deletions Sources/Core.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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()
}
}
Expand Down Expand Up @@ -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 by `allowScrollPanGesture(of:condition:)`.
// If not reset, the following logic to shift the surface frame doesn't work and then the scroll content
// offset becomes 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:
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 3c6ee6f

Please sign in to comment.