Skip to content

Commit bb1d637

Browse files
committed
Fix an issue scrolling jumps with a small scroll view content(#524)
Commit 448fc5c has a critical regression in scroll tracking that can cause the scroll content to bounce after moving a panel, for example, pulling down it from full to half state. By re-investigating #524, I found that this problem only occurred with the fitToBounds content mode(and a small scroll view content). Therefore I fixed it in the more specific way.
1 parent 8aaaac3 commit bb1d637

File tree

1 file changed

+29
-6
lines changed

1 file changed

+29
-6
lines changed

Sources/Core.swift

+29-6
Original file line numberDiff line numberDiff line change
@@ -459,15 +459,15 @@ class Core: NSObject, UIGestureRecognizerDelegate {
459459
switch layoutAdapter.position {
460460
case .top, .left:
461461
if velocity < 0, !allowScrollPanGesture(for: scrollView) {
462-
lockScrollView()
462+
lockScrollView(strict: true)
463463
}
464464
if velocity > 0, allowScrollPanGesture(for: scrollView) {
465465
unlockScrollView()
466466
}
467467
case .bottom, .right:
468468
// Hide a scroll indicator just before starting an interaction by swiping a panel down.
469469
if velocity > 0, !allowScrollPanGesture(for: scrollView) {
470-
lockScrollView()
470+
lockScrollView(strict: true)
471471
}
472472
// Show a scroll indicator when an animation is interrupted at the top and content is scrolled up
473473
if velocity < 0, allowScrollPanGesture(for: scrollView) {
@@ -930,13 +930,19 @@ class Core: NSObject, UIGestureRecognizerDelegate {
930930
""")
931931
if finished, state == layoutAdapter.mostExpandedState, abs(layoutAdapter.offsetFromMostExpandedAnchor) <= 1.0 {
932932
unlockScrollView()
933+
} else if finished, shouldLooselyLockScrollView {
934+
unlockScrollView()
933935
}
934936
}
935937

936938
func value(of point: CGPoint) -> CGFloat {
937939
return layoutAdapter.position.mainLocation(point)
938940
}
939941

942+
func value(of size: CGSize) -> CGFloat {
943+
return layoutAdapter.position.mainDimension(size)
944+
}
945+
940946
func setValue(_ newValue: CGPoint, to point: inout CGPoint) {
941947
switch layoutAdapter.position {
942948
case .top, .bottom:
@@ -1024,7 +1030,7 @@ class Core: NSObject, UIGestureRecognizerDelegate {
10241030
scrollView.transform = CGAffineTransform(translationX: 0, y: contentOffset)
10251031
}
10261032

1027-
private func lockScrollView() {
1033+
private func lockScrollView(strict: Bool = false) {
10281034
guard let scrollView = scrollView else { return }
10291035

10301036
if scrollView.isLocked {
@@ -1033,23 +1039,40 @@ class Core: NSObject, UIGestureRecognizerDelegate {
10331039
}
10341040
log.debug("lock scroll view")
10351041

1036-
scrollBounce = scrollView.bounces
10371042
scrollIndictorVisible = scrollView.showsVerticalScrollIndicator
10381043

1044+
if !strict, shouldLooselyLockScrollView {
1045+
// Don't change its `bounces` property. If it's changed, it will make its content offset jump at the most
1046+
// expanded anchor when seamlessly scrolling content. This problem only occurs where its content mode is
1047+
// `.fitToBounds` and the tracking scroll content is smaller than the content view size.
1048+
} else {
1049+
scrollBounce = scrollView.bounces
1050+
scrollView.bounces = false
1051+
}
10391052
scrollView.isDirectionalLockEnabled = true
1040-
scrollView.bounces = false
10411053
scrollView.showsVerticalScrollIndicator = false
10421054
}
10431055

10441056
private func unlockScrollView() {
10451057
guard let scrollView = scrollView, scrollView.isLocked else { return }
10461058
log.debug("unlock scroll view")
10471059

1048-
scrollView.isDirectionalLockEnabled = false
10491060
scrollView.bounces = scrollBounce
1061+
scrollView.isDirectionalLockEnabled = false
10501062
scrollView.showsVerticalScrollIndicator = scrollIndictorVisible
10511063
}
10521064

1065+
private var shouldLooselyLockScrollView: Bool {
1066+
var isSmallScrollContentAndFitToBoundsMode: Bool {
1067+
if ownerVC?.contentMode == .fitToBounds, let scrollView = scrollView,
1068+
value(of: scrollView.contentSize) < value(of: scrollView.bounds.size) - min(layoutAdapter.offsetFromMostExpandedAnchor, 0) {
1069+
return true
1070+
}
1071+
return false
1072+
}
1073+
return isSmallScrollContentAndFitToBoundsMode
1074+
}
1075+
10531076
private func stopScrolling(at contentOffset: CGPoint) {
10541077
// Must use setContentOffset(_:animated) to force-stop deceleration
10551078
guard let scrollView = scrollView else { return }

0 commit comments

Comments
 (0)