Duplicate view controllers when using nav controllers inside page view controller - ios

Courtesy of Using UIPageViewController with swift and multiple view controllers, I'm embedding navigation controllers in a UIPageViewController so I can horizontally scroll thru them (like swipe nav). Problem:
When I reach the first or last nav controller, and then swipe in the opposite direction, the 2nd-to-first/last nav controller will duplicate. So I'll have 5 nav controllers. For example:
Starting at FirstNav, swipe left all the way to FourthNav. When I swipe right through the array of controllers from FourthNav, the sequence will be: ThirdNav, ThirdNav, SecondNav, FirstNav. Can anyone find out what's going on?
class PageViewController: UIPageViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate {
var index = 0
var identifiers: NSArray = ["FirstNav", "SecondNav", "ThirdNav", "FourthNav"]
override func viewDidLoad() {
super.viewDidLoad()
self.dataSource = self
self.delegate = self
let startingViewController = self.viewControllerAtIndex(self.index)
let viewControllers: NSArray = [startingViewController]
self.setViewControllers(viewControllers as [AnyObject], direction: UIPageViewControllerNavigationDirection.Forward, animated: false, completion: nil)
}
func viewControllerAtIndex(index: Int) -> UINavigationController! {
if index == 0 {
return self.storyboard!.instantiateViewControllerWithIdentifier("FirstNav") as! UINavigationController
}
if index == 1 {
return self.storyboard!.instantiateViewControllerWithIdentifier("SecondNav") as! UINavigationController
}
if index == 2 {
return self.storyboard!.instantiateViewControllerWithIdentifier("ThirdNav") as! UINavigationController
}
if index == 3 {
return self.storyboard!.instantiateViewControllerWithIdentifier("FourthNav") as! UINavigationController
}
return nil
}
func pageViewController(pageViewController: UIPageViewController, viewControllerAfterViewController viewController: UIViewController) -> UIViewController? {
let identifier = viewController.restorationIdentifier
let index = self.identifiers.indexOfObject(identifier!)
//if the index is the end of the array, return nil since we dont want a view controller after the last one
if index == identifiers.count - 1 {
return nil
}
//increment the index to get the viewController after the current index
self.index = self.index + 1
return self.viewControllerAtIndex(self.index)
}
func pageViewController(pageViewController: UIPageViewController, viewControllerBeforeViewController viewController: UIViewController) -> UIViewController? {
let identifier = viewController.restorationIdentifier
let index = self.identifiers.indexOfObject(identifier!)
//if the index is 0, return nil since we dont want a view controller before the first one
if index == 0 {
return nil
}
//decrement the index to get the viewController before the current one
self.index = self.index - 1
return self.viewControllerAtIndex(self.index)
}
func presentationCountForPageViewController(pageViewController: UIPageViewController) -> Int {
return 0
}
func presentationIndexForPageViewController(pageViewController: UIPageViewController) -> Int {
return 0
}
}

The issue has to do with your calculation of the index variable in your pageViewController(_:viewControllerBeforeViewController:) and pageViewController(_:viewControllerAfterViewController:) methods. To simplify that logic and the overall logic of your page view controller, you should change your implementation to the following:
class PageViewController: UIPageViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate {
private var pages: [UIViewController]!
override func viewDidLoad() {
super.viewDidLoad()
self.dataSource = self
self.delegate = self
self.pages = [
self.storyboard!.instantiateViewControllerWithIdentifier("FirstNav") as! UINavigationController,
self.storyboard!.instantiateViewControllerWithIdentifier("SecondNav") as! UINavigationController,
self.storyboard!.instantiateViewControllerWithIdentifier("ThirdNav") as! UINavigationController,
self.storyboard!.instantiateViewControllerWithIdentifier("FourthNav") as! UINavigationController
]
let startingViewController = self.pages.first! as UIViewController
self.setViewControllers([startingViewController], direction: .Forward, animated: false, completion: nil)
}
func pageViewController(pageViewController: UIPageViewController, viewControllerAfterViewController viewController: UIViewController) -> UIViewController? {
let index = (self.pages as NSArray).indexOfObject(viewController)
// if currently displaying last view controller, return nil to indicate that there is no next view controller
return (index == self.pages.count - 1 ? nil : self.pages[index + 1])
}
func pageViewController(pageViewController: UIPageViewController, viewControllerBeforeViewController viewController: UIViewController) -> UIViewController? {
let index = (self.pages as NSArray).indexOfObject(viewController)
// if currently displaying first view controller, return nil to indicate that there is no previous view controller
return (index == 0 ? nil : self.pages[index - 1])
}
}
You don't even need to maintain an index instance variable, and this implementation does not do so. But you could, if you wanted. This solution also instantiates a single instance of each UINavigationController instead of instantiating a new one every time the user attempts to scroll to a different page, which conserves memory and preserves the state of the view controllers as the user scrolls between them.
Please excuse the non-descriptive pages variable name. I didn't want to create a conflict with UIPageViewController's viewControllers property.

Related

add observer and selector method not executing

When the user clicked in a cell it will go to the detail view controller here I post a notification with the selected index(object of a class). In detail view controller I used a container view. In this container view, I used a page view controller having two view controllers let's say A and B correspondingly. Both these two view controllers I created add observer method. But only 'A' view controller is registering for the notification. How can I get the selected index(object of a class) in B view controller..?
Code of detail View controller
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.post(name: Notification.Name(rawValue: mynotificationkey), object: nil, userInfo: ["object": self.treatobj])
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "pageView2" {
if let destination = segue.destination as? PageViewController {
destination.treatmentObject = treatobj
}
}
}
code of First View Controller that its executing fine
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(display(notification:)), name: Notification.Name(rawValue: mynotificationkey), object: nil)
}
override func viewWillDisappear(_ animated: Bool) {
NotificationCenter.default.removeObserver(self)
}
func display(notification: Notification){
if let object = notification.userInfo {
if let obj = object["object"] {
treatObject = obj as! TreatMents
print(treatObject)
self.detailTitleLabel.text = treatObject.trtName
self.DesctextView.text = treatObject.desc1
}
}
}
code of second view controller that does not execute add observer
override func viewDidLoad() {
super.viewDidLoad()
about.text = treatObj.aboutkerala
//benifits = treatObj.benifits!
NotificationCenter.default.addObserver(self, selector: #selector(notfrecieved(notification:)), name: NSNotification.Name(rawValue: mynotificationkey), object: nil)
// Do any additional setup after loading the view.
}
func notfrecieved(notification: Notification) {
if let object = notification.userInfo {
if let obj = object["object"] {
print(obj)
treatObj = obj as! TreatMents
about.text = treatObj.aboutkerala
benifits = treatObj.benifits!
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
}
}
code of Page view controller
class PageViewController: UIPageViewController, UIPageViewControllerDelegate, UIPageViewControllerDataSource {
var treatmentObject = TreatMents()
lazy var VCArray : [UIViewController] = {
return [self.VCInstance(name: "DescFisrtVC"),
self.VCInstance(name: "DescSecondVC"),
]
}()
private func VCInstance(name: String) -> UIViewController {
return UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: name)
}
public func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
guard let viewControllerIndex = VCArray.index(of: viewController) else {
return nil
}
let previousIndex = viewControllerIndex - 1
guard previousIndex >= 0 else {
return VCArray.last
}
guard VCArray.count > previousIndex else {
return nil
}
return VCArray[previousIndex]
}
public func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
guard let viewControllerIndex = VCArray.index(of: viewController) else {
return nil
}
let nextIndex = viewControllerIndex + 1
guard nextIndex < VCArray.count else {
return VCArray.first
}
guard VCArray.count > nextIndex else {
return nil
}
return VCArray[nextIndex]
}
// A page indicator will be visible if both methods are implemented, transition style is 'UIPageViewControllerTransitionStyleScroll', and navigation orientation is 'UIPageViewControllerNavigationOrientationHorizontal'.
// Both methods are called in response to a 'setViewControllers:...' call, but the presentation index is updated automatically in the case of gesture-driven navigation.
public func presentationCount(for pageViewController: UIPageViewController) -> Int {
return VCArray.count
}
public func presentationIndex(for pageViewController: UIPageViewController) -> Int {
guard let firstViewController = viewControllers?.first, let firstViewcontrollerIndex = VCArray.index(of: firstViewController) else {
return 0
}
return firstViewcontrollerIndex
}
override func viewDidLoad() {
super.viewDidLoad()
self.dataSource = self
self.delegate = self
if let firstVc = VCArray.first {
setViewControllers([firstVc], direction: .forward, animated: true, completion: nil)
}
// Do any additional setup after loading the view.
}
If you want to NotificationCenter then you need to load that class in memory first .
If you are added NotificationCenter in class but that class not loaded so this will be not working .
From the flow it looks to me that the two VCs in UIPageViewControllers didn't load yet when you are posting the notification.
Have a look at the explanation given in doc:
When defining a page view controller interface, you can provide the
content view controllers one at a time (or two at a time, depending
upon the spine position and double-sided state) or as-needed using a
data source. When providing content view controllers one at a time,
you use the setViewControllers(_:direction:animated:completion:)
method to set the current content view controllers. To support
gesture-based navigation, you must provide your view controllers using
a data source object.
So my guess is that since one page is loaded at a time, so your second controller didn't register for this event.
I have an objection on this process design using NSNotification, since from your code it looks to me that you want to evaluate your TreatMents objects on both screen when they gets load, IMHO you can either use Singleton concept (using session) or use KVO to fix this problem.
EDIT:
In PageViewController you implement these two functions:
public func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController?
public func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController?
that returns a VC from VCArray like:
return VCArray[previousIndex]
You also have treatmentObject in PageViewController, can you pass this variable to your two viewcontrollers while fetching it in above delegate functions like:
public func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
guard let viewControllerIndex = VCArray.index(of: viewController) else {
return nil
}
let previousIndex = viewControllerIndex - 1
guard previousIndex >= 0 else {
return VCArray.last
}
guard VCArray.count > previousIndex else {
return nil
}
let VC = VCArray[previousIndex] // <------ Check this out
VC.treatObj = self.treatmentObject; // <------ Check this out
return VC
}
Or you can also save your selected treatment in session and retrieve it in two view controllers.

Remove Black Edges from UIPageViewController in Swift 3

I am using Swift 3.0 and have created a UIPageViewController currently with two pages (each one is a UIViewController). When I run the app, everything works fine, except that there are black spaces at the bottom and the right side of the app when the ViewControllers are shown. I also cannot see the page dots in the PageViewController. I have implemented the functions to place the dots on the screen:
func pageViewController(pageViewController: PageViewController,
didUpdatePageCount count: Int)
func pageViewController(pageViewController: PageViewController,
didUpdatePageIndex index: Int)
Layout
View Controller Inside the PageViewController
PageViewController Settings
Would anyone know how to fix the black borders around the pages and add the page dots?
Update
import UIKit
class PageViewController: UIPageViewController {
weak var pageDelegate: PageViewControllerDelegate?
private(set) lazy var orderedViewControllers: [UIViewController] = {
// The view controllers will be shown in this order
return [self.newViewController(name: "view1"),
self.newViewController(name: "view2"),
self.newViewController(name: "view3"),
self.newViewController(name: "view4"),
self.newViewController(name: "view5")]
}()
override func viewDidLoad() {
super.viewDidLoad()
dataSource = self
delegate = self
if let initialViewController = orderedViewControllers.first {
scrollToViewController(viewController: initialViewController, direction: UIPageViewControllerNavigationDirection.forward)
}
pageDelegate?.pageViewController(pageViewController: self, didUpdatePageCount: orderedViewControllers.count)
}
/**
Scrolls to the next view controller.
*/
func scrollToNextViewController() {
if let visibleViewController = viewControllers?.first,
let nextViewController = pageViewController(self, viewControllerAfter: visibleViewController) {
scrollToViewController(viewController: nextViewController, direction: UIPageViewControllerNavigationDirection.forward)
}
}
/**
Scrolls to the view controller at the given index. Automatically calculates
the direction.
- parameter newIndex: the new index to scroll to
*/
func scrollToViewController(index newIndex: Int) {
if let firstViewController = viewControllers?.first,
let currentIndex = orderedViewControllers.index(of: firstViewController) {
let direction: UIPageViewControllerNavigationDirection = newIndex >= currentIndex ? .forward : .reverse
let nextViewController = orderedViewControllers[newIndex]
scrollToViewController(viewController: nextViewController, direction: direction)
}
}
private func newViewController(name: String) -> UIViewController {
return UIStoryboard(name: "Main", bundle: nil) .
instantiateViewController(withIdentifier: "\(name)ViewController")
}
/**
Scrolls to the given 'viewController' page.
- parameter viewController: the view controller to show.
*/
private func scrollToViewController(viewController: UIViewController,
direction: UIPageViewControllerNavigationDirection = .forward) {
setViewControllers([viewController],
direction: direction,
animated: true,
completion: { (finished) -> Void in
// Setting the view controller programmatically does not fire
// any delegate methods, so we have to manually notify the
// 'pageDelegate' of the new index.
self.notifyPageDelegateOfNewIndex()
})
}
/**
Notifies '_pageDelegate' that the current page index was updated.
*/
func notifyPageDelegateOfNewIndex() {
if let firstViewController = viewControllers?.first,
let index = orderedViewControllers.index(of: firstViewController) {
self.pageDelegate?.pageViewController(pageViewController: self, didUpdatePageIndex: index)
}
}
}
// MARK: UIPageViewControllerDataSource
extension PageViewController: UIPageViewControllerDataSource {
func pageViewController(_ pageViewController: UIPageViewController,
viewControllerBefore viewController: UIViewController) -> UIViewController? {
guard let viewControllerIndex = orderedViewControllers.index(of: viewController) else {
return nil
}
let previousIndex = viewControllerIndex - 1
// User is on the first view controller and swiped left to loop to
// the last view controller.
guard previousIndex >= 0 else {
return orderedViewControllers.last
}
guard orderedViewControllers.count > previousIndex else {
return nil
}
return orderedViewControllers[previousIndex]
}
func pageViewController(_ pageViewController: UIPageViewController,
viewControllerAfter viewController: UIViewController) -> UIViewController? {
guard let viewControllerIndex = orderedViewControllers.index(of: viewController) else {
return nil
}
let nextIndex = viewControllerIndex + 1
let orderedViewControllersCount = orderedViewControllers.count
// User is on the last view controller and swiped right to loop to
// the first view controller.
guard orderedViewControllersCount != nextIndex else {
return orderedViewControllers.first
}
guard orderedViewControllersCount > nextIndex else {
return nil
}
return orderedViewControllers[nextIndex]
}
}
extension PageViewController: UIPageViewControllerDelegate {
func pageViewController(_ pageViewController: UIPageViewController,
didFinishAnimating finished: Bool,
previousViewControllers: [UIViewController],
transitionCompleted completed: Bool) {
notifyPageDelegateOfNewIndex()
}
}
protocol PageViewControllerDelegate: class {
/**
Called when the number of pages is updated.
- parameter pageViewController: the PageViewController instance
- parameter count: the total number of pages.
*/
func pageViewController(pageViewController: PageViewController,
didUpdatePageCount count: Int)
/**
Called when the current index is updated.
- parameter pageViewController: the PageViewController instance
- parameter index: the index of the currently visible page.
*/
func pageViewController(pageViewController: PageViewController,
didUpdatePageIndex index: Int)
}
I had the same issue now, I've just solved that problem by changing the background color to white in the viewDidLoad() function
self.view.backgroundColor = .white

Swift and Page view controller between 2 views

in my swift iOS app i would create a storyboard with two views. I want use the page view controller element, so, with one left / right swipe, the user can change the actual view. How can I do this?
IMPORTANT! I have searched several time for tutorials in the web. I have only found schema which allow to change images in the same image view. I don't want to change the image in the same image in the same view; i want change the entire view. I attach a image, to better explain.
Thank in advance]1
This explains how to create a paged view controller using storyboard:
Drag a UIPageViewController into storyboard and mark it as the initial view controller.
Then create a new UIPageViewController subclass - say call it TutorialPageViewController and assign it to the object you just dragged into storyboard.
Now drag in two new UIViewControllers into storyboard and create/assign a subclass for each, as you would do normally.
Give each of these two view controllers a Storyboard ID e.g RedViewController & GreenViewController.
Now add this code in your TutorialPageViewController which creates
and shows the correct view controller when you swipe:
TutorialPageViewController:
class TutorialPageViewController: UIPageViewController, UIPageViewControllerDataSource {
private(set) lazy var orderedViewControllers: [UIViewController] = {
return [self.newColoredViewController("RedViewController"),
self.newColoredViewController("GreenViewController")]
}()
private func newColoredViewController(color: String) -> UIViewController {
return UIStoryboard(name: "Main", bundle: nil) .
instantiateViewControllerWithIdentifier("\(color)ViewController")
}
override func viewDidLoad() {
super.viewDidLoad()
dataSource = self
if let firstViewController = orderedViewControllers.first {
setViewControllers([firstViewController],
direction: .Forward,
animated: true,
completion: nil)
}
}
func pageViewController(pageViewController: UIPageViewController,
viewControllerBeforeViewController viewController: UIViewController) -> UIViewController? {
guard let viewControllerIndex = orderedViewControllers.indexOf(viewController) else {
return nil
}
let previousIndex = viewControllerIndex - 1
guard previousIndex >= 0 else {
return nil
}
guard orderedViewControllers.count > previousIndex else {
return nil
}
return orderedViewControllers[previousIndex]
}
func pageViewController(pageViewController: UIPageViewController,
viewControllerAfterViewController viewController: UIViewController) -> UIViewController? {
guard let viewControllerIndex = orderedViewControllers.indexOf(viewController) else {
return nil
}
let nextIndex = viewControllerIndex + 1
let orderedViewControllersCount = orderedViewControllers.count
guard orderedViewControllersCount != nextIndex else {
return nil
}
guard orderedViewControllersCount > nextIndex else {
return nil
}
return orderedViewControllers[nextIndex]
}
}
See the article for more details and a tutorial on this.
https://spin.atomicobject.com/2015/12/23/swift-uipageviewcontroller-tutorial/
Update: Page Dots
Read from point 7 on this part 2 article that shows how to add a UIPageControl and change the dots on swipe:
https://spin.atomicobject.com/2016/02/11/move-uipageviewcontroller-dots/
#IBOutlet weak var pageControl: UIPageControl!
func tutorialPageViewController(tutorialPageViewController: TutorialPageViewController,
didUpdatePageCount count: Int) {
pageControl.numberOfPages = count
}
func tutorialPageViewController(tutorialPageViewController: TutorialPageViewController,
didUpdatePageIndex index: Int) {
pageControl.currentPage = index
}

Change index of VC in page view controller (Swift)

Using the following code, I have a series of view controllers embedded in a page view controller that I'm swiping through. I just can't find a way to segue to another view controller via a bar button press. I'm planning on writing a separate function for each bar button icon in each view controller.
class PageViewController: UIPageViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate {
private var pages: [UIViewController]!
override func viewDidLoad() {
super.viewDidLoad()
self.dataSource = self
self.delegate = self
self.pages = [
self.storyboard!.instantiateViewControllerWithIdentifier("FirstNav") as! UINavigationController,
self.storyboard!.instantiateViewControllerWithIdentifier("SecondNav") as! UINavigationController,
self.storyboard!.instantiateViewControllerWithIdentifier("ThirdNav") as! UINavigationController,
self.storyboard!.instantiateViewControllerWithIdentifier("FourthNav") as! UINavigationController
]
let startingViewController = self.pages.first! as UIViewController
self.setViewControllers([startingViewController], direction: .Forward, animated: false, completion: nil)
}
func pageViewController(pageViewController: UIPageViewController, viewControllerAfterViewController viewController: UIViewController) -> UIViewController? {
let index = (self.pages as NSArray).indexOfObject(viewController)
// if currently displaying last view controller, return nil to indicate that there is no next view controller
return (index == self.pages.count - 1 ? nil : self.pages[index + 1])
}
func pageViewController(pageViewController: UIPageViewController, viewControllerBeforeViewController viewController: UIViewController) -> UIViewController? {
let index = (self.pages as NSArray).indexOfObject(viewController)
// if currently displaying first view controller, return nil to indicate that there is no previous view controller
return (index == 0 ? nil : self.pages[index - 1])
}
}
Change your implementation of PageViewController to the following (I made some changes in the methods you already implemented, and I added a new instance method.)
class PageViewController: UIPageViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate {
private var pages: [UINavigationController]!
private var currentPageIndex: Int!
override func viewDidLoad() {
super.viewDidLoad()
self.dataSource = self
self.delegate = self
self.pages = [
self.storyboard!.instantiateViewControllerWithIdentifier("FirstNav") as! UINavigationController,
self.storyboard!.instantiateViewControllerWithIdentifier("SecondNav") as! UINavigationController,
self.storyboard!.instantiateViewControllerWithIdentifier("ThirdNav") as! UINavigationController,
self.storyboard!.instantiateViewControllerWithIdentifier("FourthNav") as! UINavigationController
]
(self.pages[0].topViewController as! FirstViewController).parentPageViewController = self
(self.pages[1].topViewController as! SecondViewController).parentPageViewController = self
(self.pages[2].topViewController as! ThirdViewController).parentPageViewController = self
(self.pages[3].topViewController as! FourthViewController).parentPageViewController = self
self.currentPageIndex = 0
let startingViewController = self.pages.first! as UINavigationController
self.setViewControllers([startingViewController], direction: .Forward, animated: false, completion: nil)
}
func pageViewController(pageViewController: UIPageViewController, viewControllerAfterViewController viewController: UIViewController) -> UIViewController? {
let index = (self.pages as NSArray).indexOfObject(viewController)
self.currentPageIndex = index
// if currently displaying last view controller, return nil to indicate that there is no next view controller
return (self.currentPageIndex == self.pages.count - 1 ? nil : self.pages[self.currentPageIndex + 1])
}
func pageViewController(pageViewController: UIPageViewController, viewControllerBeforeViewController viewController: UIViewController) -> UIViewController? {
let index = (self.pages as NSArray).indexOfObject(viewController)
self.currentPageIndex = index
// if currently displaying first view controller, return nil to indicate that there is no previous view controller
return (index == 0 ? nil : self.pages[index - 1])
}
func displayPageForIndex(index: Int, animated: Bool = true) {
assert(index >= 0 && index < self.pages.count, "Error: Attempting to display a page for an out of bounds index")
// nop if index == self.currentPageIndex
if self.currentPageIndex == index { return }
if index < self.currentPageIndex {
self.setViewControllers([self.pages[index]], direction: .Reverse, animated: true, completion: nil)
} else if index > self.currentPageIndex {
self.setViewControllers([self.pages[index]], direction: .Forward, animated: true, completion: nil)
}
self.currentPageIndex = index
}
}
Now, in each of your child view controllers, add two pieces of code:
A property that maintains a weak reference to the parent PageViewController instance.
weak var parentPageViewController: PageViewController!
An IBAction to which you connect each of your bar button items. You may need to change the body of this method depending on how your Storyboard is set up.
#IBAction func barButtonTapped(sender: UIBarButtonItem) {
var newIndex = -1
switch sender.title! {
case "First":
newIndex = 0
case "Second":
newIndex = 1
case "Third":
newIndex = 2
case "Fourth":
newIndex = 3
default: break
}
self.parentPageViewController.displayPageForIndex(newIndex)
}
Does each controller need to be embedded in a UINavigationController? You could just have a UINavigationController embed a single UIViewController, that view controller references a pageviewcontroller and a barButtonItem, when the barButtonItem is tapped trigger an action that tells the pageviewcontroller to change indexes.
Or if you want to go with your current plan of action which is a barButtonItem in each UINavigationController, write a protocol with a delegate method didSelectBarButtonAtIndex or something, then give each UINavigationController a delegate property, have the pageviewcontroller conform to the protocol and become the delegate for each nav controller. Then when a bar button is tapped, call the delegate method, which should make the page controller change it's index.

Swift - Implementing PageViewController in one UIViewController

Nowhere in internet is explain how to implement PageViewController in your UIViewController
I take this code from default XCode Page-Based Application
class ViewController: UIViewController, UIPageViewControllerDelegate, UIPageViewControllerDataSource {
var pageViewController: UIPageViewController?
override func viewDidLoad() {
self.pageViewController = UIPageViewController(transitionStyle: .PageCurl, navigationOrientation: .Horizontal, options: nil)
self.pageViewController!.delegate = self
self.view.addSubview(self.pageViewController!.view)
// Set the page view controller's bounds using an inset rect so that self's view is visible around the edges of the pages.
var pageViewRect = self.view.bounds
self.pageViewController!.view.frame = pageViewRect
self.pageViewController!.didMoveToParentViewController(self)
// Add the page view controller's gesture recognizers to the book view controller's view so that the gestures are started more easily.
self.view.gestureRecognizers = self.pageViewController!.gestureRecognizers
}
func pageViewController(pageViewController: UIPageViewController, viewControllerBeforeViewController viewController: UIViewController) -> UIViewController? {
//?? what controller should I return
}
func pageViewController(pageViewController: UIPageViewController, viewControllerAfterViewController viewController: UIViewController) -> UIViewController? {
//?? what controller should I return
}
}
I want to have 6 pages and I want to add text in different pages how to recognize in which page I am and show the info that I want? I want to use only 1 ViewControler, only this view controller.
UIPageViewController requires that you use different view controllers. You may need to refactor your code to have a "parent" or "root" view controller, whose only job is to present other view controllers that implement the logic for specific pages. Here's some sample code. It's oversimplified but should give you an idea of how to get going.
class PageContent {
let text: String
let index: Int
init(text: String, index: Int) {
self.text = text
self.index = index
}
}
class MyPageViewController : UIViewController {
var page: PageContent!
override func viewDidLoad() {
// Load page data for self.page
}
}
class ViewController: UIViewController, UIPageViewControllerDelegate, UIPageViewControllerDataSource {
var pageViewController: UIPageViewController?
var pages: [PageContent]!
override func viewDidLoad() {
let firstPage = PageContent(text: "...", index: 0)
let secondPage = PageContent(text: "...", index: 1)
// ...
self.pages = [firstPage, secondPage] // add more as necessary
}
func pageViewController(pageViewController: UIPageViewController, viewControllerBeforeViewController viewController: UIViewController) -> UIViewController? {
let beforeController = viewController as MyPageViewController
let newPageIndex = beforeController.page.index - 1
if newPageIndex >= 0 {
let newController = MyPageViewController()
newController.page = self.pages[newPageIndex]
return newController
} else {
return nil
}
}
func pageViewController(pageViewController: UIPageViewController, viewControllerAfterViewController viewController: UIViewController) -> UIViewController? {
let afterController = viewController as MyPageViewController
let newPageIndex = afterController.page.index + 1
if newPageIndex < self.pages.count {
let newController = MyPageViewController()
newController.page = self.pages[newPageIndex]
return newController
} else {
return nil
}
}
}

Resources