Reputation: 2790
I programatically wrote a UIPageViewController
into my iOS app. However, when I set the next ViewController like this:
pageContainer.setViewControllers([pages[currentIndex + 1]], direction: UIPageViewControllerNavigationDirection.reverse, animated: true, completion: nil)
my entire app crashes.
Now from what I found, there are two fixes to this problem:
UIPageViewController
's transitionStyle
to .pageCurl
(which provides me with an incredibly ugly and unwanted animation)animated
property to false when setting as new ViewController (Which then gives me no animation whatsoever, and thus is also unwanted)..Does anyone know a way around this? Since neither of these options is probably gonna fly with my client...
Thanks!
-- Edit
As asked: The crash message:
2018-02-25 13:09:25.728651+0100 WAMP[22669:601029] *** Assertion failure in -[UIPageViewController _flushViewController:animated:], /BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKit_Sim/UIKit-3698.33.6/UIPageViewController.m:2137
2018-02-25 13:09:25.855963+0100 WAMP[22669:601029] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Don't know about flushed view <UIView: 0x7fcdc5d167c0; frame = (0 0; 375 667); autoresize = W+H; gestureRecognizers = <NSArray: 0x600000644b90>; layer = <CALayer: 0x60000022daa0>>'
A complete code sample:
class OnboardingViewController: UIViewController, UIPageViewControllerDelegate {
var pageContainer: UIPageViewController!
var currentIndex: Int? = 0
var pendingIndex: Int?
private(set) lazy var pages: [UIViewController] = {
return [self.newStep(step: "One"), self.newStep(step: "Two"), self.newStep(step: "Three"), self.newStep(step: "Four")]
}()
override func viewDidLoad() {
super.viewDidLoad()
pageContainer = UIPageViewController(transitionStyle: .scroll, navigationOrientation: .horizontal, options: nil)
pageContainer.delegate = self
pageContainer.setViewControllers([pages[0]], direction: UIPageViewControllerNavigationDirection.forward, animated: true, completion: nil)
view.addSubview(pageContainer.view)
}
@IBAction func nextButtonPressed(_ sender: Any) {
self.pendingIndex = (self.currentIndex!) + 1
self.currentIndex = (self.currentIndex!) + 1
self.pageContainer.setViewControllers([self.pages[self.currentIndex!]], direction: UIPageViewControllerNavigationDirection.forward, animated: true, completion: nil)
}
private func newStep(step: String) -> UIViewController {
return UIStoryboard(name: "Onboarding", bundle: nil).instantiateViewController(withIdentifier: "onboardingStep\(step)")
}
func pageViewController(_ pageViewController: UIPageViewController,
viewControllerBefore viewController: UIViewController) -> UIViewController? {
let currentIndex = pages.index(of: viewController)!
if currentIndex == 0 {
return nil
}
let previousIndex = abs((currentIndex - 1) % pages.count)
return pages[previousIndex]
}
func pageViewController(_ pageViewController: UIPageViewController,
viewControllerAfter viewController: UIViewController) -> UIViewController? {
let currentIndex = pages.index(of: viewController)!
if currentIndex == pages.count-1 {
return nil
}
let nextIndex = abs((currentIndex + 1) % pages.count)
return pages[nextIndex]
}
func pageViewController(_ pageViewController: UIPageViewController, willTransitionTo pendingViewControllers: [UIViewController]) {
pendingIndex = pages.index(of: pendingViewControllers.first!)
}
func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
if completed {
currentIndex = pendingIndex
}
}
}
Upvotes: 2
Views: 2235
Reputation: 601
I think you need to set up the data souse of UIPageViewController before setting view controllers directly. Transition style .scroll is required data source for page caching.
override func viewDidLoad() {
super.viewDidLoad()
pageContainer = UIPageViewController(transitionStyle: .scroll, navigationOrientation: .horizontal, options: nil)
pageContainer.delegate = self
pageContainer.dataSource = self
pageContainer.setViewControllers([pages[0]], direction: UIPageViewControllerNavigationDirection.forward, animated: true, completion: nil)
view.addSubview(pageContainer.view)
}
Upvotes: 1