@@ -459,15 +459,15 @@ class Core: NSObject, UIGestureRecognizerDelegate {
459
459
switch layoutAdapter. position {
460
460
case . top, . left:
461
461
if velocity < 0 , !allowScrollPanGesture( for: scrollView) {
462
- lockScrollView ( )
462
+ lockScrollView ( strict : true )
463
463
}
464
464
if velocity > 0 , allowScrollPanGesture ( for: scrollView) {
465
465
unlockScrollView ( )
466
466
}
467
467
case . bottom, . right:
468
468
// Hide a scroll indicator just before starting an interaction by swiping a panel down.
469
469
if velocity > 0 , !allowScrollPanGesture( for: scrollView) {
470
- lockScrollView ( )
470
+ lockScrollView ( strict : true )
471
471
}
472
472
// Show a scroll indicator when an animation is interrupted at the top and content is scrolled up
473
473
if velocity < 0 , allowScrollPanGesture ( for: scrollView) {
@@ -930,13 +930,19 @@ class Core: NSObject, UIGestureRecognizerDelegate {
930
930
""" )
931
931
if finished, state == layoutAdapter. mostExpandedState, abs ( layoutAdapter. offsetFromMostExpandedAnchor) <= 1.0 {
932
932
unlockScrollView ( )
933
+ } else if finished, shouldLooselyLockScrollView {
934
+ unlockScrollView ( )
933
935
}
934
936
}
935
937
936
938
func value( of point: CGPoint ) -> CGFloat {
937
939
return layoutAdapter. position. mainLocation ( point)
938
940
}
939
941
942
+ func value( of size: CGSize ) -> CGFloat {
943
+ return layoutAdapter. position. mainDimension ( size)
944
+ }
945
+
940
946
func setValue( _ newValue: CGPoint , to point: inout CGPoint ) {
941
947
switch layoutAdapter. position {
942
948
case . top, . bottom:
@@ -1024,7 +1030,7 @@ class Core: NSObject, UIGestureRecognizerDelegate {
1024
1030
scrollView. transform = CGAffineTransform ( translationX: 0 , y: contentOffset)
1025
1031
}
1026
1032
1027
- private func lockScrollView( ) {
1033
+ private func lockScrollView( strict : Bool = false ) {
1028
1034
guard let scrollView = scrollView else { return }
1029
1035
1030
1036
if scrollView. isLocked {
@@ -1033,23 +1039,40 @@ class Core: NSObject, UIGestureRecognizerDelegate {
1033
1039
}
1034
1040
log. debug ( " lock scroll view " )
1035
1041
1036
- scrollBounce = scrollView. bounces
1037
1042
scrollIndictorVisible = scrollView. showsVerticalScrollIndicator
1038
1043
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
+ }
1039
1052
scrollView. isDirectionalLockEnabled = true
1040
- scrollView. bounces = false
1041
1053
scrollView. showsVerticalScrollIndicator = false
1042
1054
}
1043
1055
1044
1056
private func unlockScrollView( ) {
1045
1057
guard let scrollView = scrollView, scrollView. isLocked else { return }
1046
1058
log. debug ( " unlock scroll view " )
1047
1059
1048
- scrollView. isDirectionalLockEnabled = false
1049
1060
scrollView. bounces = scrollBounce
1061
+ scrollView. isDirectionalLockEnabled = false
1050
1062
scrollView. showsVerticalScrollIndicator = scrollIndictorVisible
1051
1063
}
1052
1064
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
+
1053
1076
private func stopScrolling( at contentOffset: CGPoint ) {
1054
1077
// Must use setContentOffset(_:animated) to force-stop deceleration
1055
1078
guard let scrollView = scrollView else { return }
0 commit comments