@@ -69,10 +69,18 @@ extension PageboyViewController: UIPageViewControllerDelegate, UIScrollViewDeleg
6969 contentOffset = scrollView. contentOffset. y
7070 }
7171
72- let scrollIndexDiff = CGFloat ( max ( 1 , abs ( ( self . expectedTransitionIndex ?? currentIndex + 1 ) - currentIndex) ) )
73- let scrollOffset = contentOffset - pageSize
74- let pageOffset = ( CGFloat ( currentIndex) * pageSize) + ( scrollOffset * scrollIndexDiff)
75- var pagePosition = pageOffset / pageSize
72+ guard let scrollIndexDiff = self . pageScrollIndexDiff ( forCurrentIndex: currentIndex,
73+ expectedIndex: self . expectedTransitionIndex,
74+ currentContentOffset: contentOffset,
75+ pageSize: pageSize) else {
76+ return
77+ }
78+
79+ guard var pagePosition = self . pagePosition ( forContentOffset: contentOffset,
80+ pageSize: pageSize,
81+ indexDiff: scrollIndexDiff) else {
82+ return
83+ }
7684
7785 // do not continue if a page change is detected
7886 guard !self . detectCurrentPageIndexIfNeeded ( pagePosition: pagePosition,
@@ -117,13 +125,11 @@ extension PageboyViewController: UIPageViewControllerDelegate, UIScrollViewDeleg
117125 ///
118126 /// - Parameter pagePosition: the relative page position.
119127 private func detectInfiniteOverscrollIfNeeded( pagePosition: inout CGFloat ) {
120- let maxPagePosition = CGFloat ( ( self . viewControllers? . count ?? 1 ) - 1 )
121- let overscrolling = pagePosition < 0.0 || pagePosition > maxPagePosition
122-
123- guard self . isInfiniteScrollEnabled && overscrolling else {
128+ guard self . isInfinitelyScrolling ( forPosition: pagePosition) else {
124129 return
125130 }
126131
132+ let maxPagePosition = CGFloat ( ( self . viewControllers? . count ?? 1 ) - 1 )
127133 var integral : Double = 0.0
128134 var progress = CGFloat ( modf ( fabs ( Double ( pagePosition) ) , & integral) )
129135 var maxInfinitePosition : CGFloat !
@@ -142,6 +148,20 @@ extension PageboyViewController: UIPageViewControllerDelegate, UIScrollViewDeleg
142148 pagePosition = infinitePagePosition
143149 }
144150
151+ /// Whether a position is infinitely scrolling between end ranges
152+ ///
153+ /// - Parameter pagePosition: The position.
154+ /// - Returns: Whether the position is infinitely scrolling.
155+ private func isInfinitelyScrolling( forPosition pagePosition: CGFloat ) -> Bool {
156+ let maxPagePosition = CGFloat ( ( self . viewControllers? . count ?? 1 ) - 1 )
157+ let overscrolling = pagePosition < 0.0 || pagePosition > maxPagePosition
158+
159+ guard self . isInfiniteScrollEnabled && overscrolling else {
160+ return false
161+ }
162+ return true
163+ }
164+
145165 /// Detects whether a page boundary has been passed.
146166 /// As pageViewController:didFinishAnimating is not reliable.
147167 ///
@@ -184,6 +204,53 @@ extension PageboyViewController: UIPageViewControllerDelegate, UIScrollViewDeleg
184204 }
185205 self . currentIndex = index
186206 }
207+
208+ /// Calculate the expected index diff for a page scroll.
209+ ///
210+ /// - Parameters:
211+ /// - index: The current index.
212+ /// - expectedIndex: The target page index.
213+ /// - currentContentOffset: The current content offset.
214+ /// - pageSize: The size of each page.
215+ /// - Returns: The expected index diff.
216+ private func pageScrollIndexDiff( forCurrentIndex index: Int ? ,
217+ expectedIndex: Int ? ,
218+ currentContentOffset: CGFloat ,
219+ pageSize: CGFloat ) -> CGFloat ? {
220+ guard let index = index else {
221+ return nil
222+ }
223+
224+ let expectedIndex = expectedIndex ?? index
225+ let expectedDiff = CGFloat ( max ( 1 , abs ( expectedIndex - index) ) )
226+ let expectedPosition = self . pagePosition ( forContentOffset: currentContentOffset,
227+ pageSize: pageSize,
228+ indexDiff: expectedDiff) ?? CGFloat ( index)
229+
230+ guard self . isInfinitelyScrolling ( forPosition: expectedPosition) == false else {
231+ return 1
232+ }
233+ return expectedDiff
234+ }
235+
236+ /// Calculate the relative page position.
237+ ///
238+ /// - Parameters:
239+ /// - contentOffset: The current contentOffset.
240+ /// - pageSize: The current page size.
241+ /// - indexDiff: The expected difference between current / target page indexes.
242+ /// - Returns: The relative page position.
243+ private func pagePosition( forContentOffset contentOffset: CGFloat ,
244+ pageSize: CGFloat ,
245+ indexDiff: CGFloat ) -> CGFloat ? {
246+ guard let currentIndex = self . currentIndex else {
247+ return nil
248+ }
249+
250+ let scrollOffset = contentOffset - pageSize
251+ let pageOffset = ( CGFloat ( currentIndex) * pageSize) + ( scrollOffset * indexDiff)
252+ return pageOffset / pageSize
253+ }
187254}
188255
189256
0 commit comments