Searched a lot for this one, but couldn\'t find a proper solution yet.
Is it possible to disable the bounce effect of a UIPageViewController
and still
Edited answer of Dong Ma, where:
currentIndex
when swipes very quickInfo:
How to:
UIViewController
where UIPageViewController
is added as child VC.class ViewController: UIViewController {
var pageNavigationController: UIPageViewController!
private var lastPosition: CGFloat
private var nextIndex: Int
var currentIndex: Int
// rest of UI's setups
}
ViewController
as delegate of UIPageViewController
:extension ViewController: UIPageViewControllerDataSource {
func pageViewController(_ pageViewController: UIPageViewController, willTransitionTo pendingViewControllers: [UIViewController]) {
guard
let currentVisibleViewController = pageViewController.viewControllers?.first,
let nextIndex = pageViewControllers.firstIndex(of: currentVisibleViewController)
else {
return
}
self.nextIndex = nextIndex
}
func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
if completed, let currentVisibleViewController = pageViewController.viewControllers?.first, let newIndex = pageViewControllers.firstIndex(of: currentVisibleViewController) {
self.currentIndex = newIndex
}
self.nextIndex = self.currentIndex
}
}
ViewController
as datasource of UIPageController
:extension ViewController: UIPageViewControllerDataSource {
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
// provide next VC
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
// provide prev VC
}
// IMPORTANT: that's the key why it works, don't forget to add it
func presentationIndex(for pageViewController: UIPageViewController) -> Int {
return currentIndex
}
}
ViewController
as delegate of UIPageViewController
's UIScrollView
:// MARK: - UIScrollViewDelegate (disable bouncing for UIPageViewController)
extension BasePaginationVC: UIScrollViewDelegate {
func attachScrollViewDelegate() {
for subview in pageNavigationController.view.subviews {
if let scrollView = subview as? UIScrollView {
scrollView.delegate = self
lastPosition = scrollView.contentOffset.x
break
}
}
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
switch UIView.userInterfaceLayoutDirection(for: view.semanticContentAttribute) {
case .leftToRight:
if nextIndex > currentIndex {
if scrollView.contentOffset.x < (lastPosition - (0.9 * scrollView.bounds.size.width)) {
currentIndex = nextIndex
}
} else {
if scrollView.contentOffset.x > (lastPosition + (0.9 * scrollView.bounds.size.width)) {
currentIndex = nextIndex
}
}
if currentIndex == 0 && scrollView.contentOffset.x < scrollView.bounds.size.width {
scrollView.contentOffset = CGPoint(x: scrollView.bounds.size.width, y: 0)
} else if currentIndex == pageViewControllers.count - 1 && scrollView.contentOffset.x > scrollView.bounds.size.width {
scrollView.contentOffset = CGPoint(x: scrollView.bounds.size.width, y: 0)
}
case .rightToLeft:
if nextIndex > currentIndex {
if scrollView.contentOffset.x > (lastPosition + (0.9 * scrollView.bounds.size.width)) {
currentIndex = nextIndex
}
} else {
if scrollView.contentOffset.x < (lastPosition - (0.9 * scrollView.bounds.size.width)) {
currentIndex = nextIndex
}
}
if currentIndex == pageViewControllers.count - 1 && scrollView.contentOffset.x < scrollView.bounds.size.width {
scrollView.contentOffset = CGPoint(x: scrollView.bounds.size.width, y: 0)
} else if currentIndex == 0 && scrollView.contentOffset.x > scrollView.bounds.size.width {
scrollView.contentOffset = CGPoint(x: scrollView.bounds.size.width, y: 0)
}
@unknown default:
fatalError("unknown default")
}
lastPosition = scrollView.contentOffset.x
}
func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer) {
switch UIView.userInterfaceLayoutDirection(for: view.semanticContentAttribute) {
case .leftToRight:
if currentIndex == 0 && scrollView.contentOffset.x <= scrollView.bounds.size.width {
targetContentOffset.pointee = CGPoint(x: scrollView.bounds.size.width, y: 0)
} else if currentIndex == pageViewControllers.count - 1 && scrollView.contentOffset.x >= scrollView.bounds.size.width {
targetContentOffset.pointee = CGPoint(x: scrollView.bounds.size.width, y: 0)
}
case .rightToLeft:
if currentIndex == pageViewControllers.count - 1 && scrollView.contentOffset.x <= scrollView.bounds.size.width {
targetContentOffset.pointee = CGPoint(x: scrollView.bounds.size.width, y: 0)
} else if currentIndex == 0 && scrollView.contentOffset.x >= scrollView.bounds.size.width {
targetContentOffset.pointee = CGPoint(x: scrollView.bounds.size.width, y: 0)
}
@unknown default:
fatalError("unknown default")
}
}
}