简体   繁体   中英

Swift 4 UIPageViewController not showing the correct views (as defined in an array in sequence

I am trying to build a small quotes app. The quotes are in an object array. Some have an article which provides some more info about the quote.

I am using 2 viewcontroller types. One has a text block for the article and the other one doesn't.

the UIPageViewController class is set up to allow the user to swipe through the quotes. This is managed by the object array above. The code goes through the array and then, if there is a string on the .article var in the object, it shows one view. If the string is blank, it shows the other one.

I can get the program to swap views, but the counter is not working correctly. This feels like a simple problem, but I'm not able to figure it out.

Bonus: My next step is to figure out how to have the view show the quote/author/article that is selected. I would also really appreciate any tips on that as well as this is all new to me. Thank you!

Here is my code

import UIKit

var thePack:[packItem] = [packItem(theQuote: "quote1", author: "", article: "hasarticle3"),packItem(theQuote: "quote2", author: "", article: ""),packItem(theQuote: "quote3", author: "", article: "hasarticle3")]

var packIndex:Int = 0

class PageViewController: UIPageViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate {

//set up the array of views to move to. All the different view types should be in here
lazy var subViewControllers:[UIViewController] = {
    return [
        UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "screen1") as! ViewController1,
        UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "screen2") as! ViewController2
    ]
}()
//end

override func viewDidLoad() {
    super.viewDidLoad()
    self.delegate = self
    self.dataSource = self

    //set up the initial viewController
    setViewControllers([subViewControllers[0]], direction: .forward, animated: true, completion: nil)
}


//set up the before view
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {

    packIndex -= 1
    if(packIndex <= 0){
        return nil
    }
    else{
        if thePack[packIndex].article != ""{
        return UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "screen1") as! ViewController1
        }

        else{
        return UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "screen2") as! ViewController2
        }
    }
}

//set up the after view
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {

    packIndex += 1

    if(packIndex >= thePack.count){
        return nil
    }
    else{
        if thePack[packIndex].article != ""{
            return UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "screen1") as! ViewController1
        }

        else{
            return UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "screen2") as! ViewController2
        }
    }
}

//change the transition style so it's not the page curl
required init?(coder: NSCoder) {
    super.init(transitionStyle: .scroll, navigationOrientation: .horizontal, options: nil)
}


//MARK UIPageViewController DataSource
func presentationCount(for pageViewController: UIPageViewController) -> Int {
    return subViewControllers.count
}

}

welcome to SO!

First of all your approach is kind of right, but the main problem is that those methods from the UIPageViewController are not called as you might expect, the thing is if you gently scroll one view controller (so it will scroll back, not go to the next position) it will call one method probably the one with viewControllerAfter but it won't call the other one when the view scrolls back, which will mess up your index. I'm not 100% sure that that's your problem but from the implementation it seems so, What I suggest, is to create a super class for all your view controllers that are displayed in the UIPageViewController and hold the page index on those. And use the page form the controllers in order to compute your position. Something like this

class MyPageViewController: UIViewController {
    var page: Int = 0
}

class OneControllerThatWillBeDisplayed: MyPageViewController {
   // do adittional things here
}


class ThePageViewController ...delegates here {

//set up the before view
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
    let theController = viewController as! MyPageViewController
    let theIndex = theController.page - 1
    if(theIndex < 0){
        return nil
    }
    else{
        if thePack[theIndex].article != ""{
            let theController =  UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "screen1") as? MyPageViewController
            theController.page = theIndex
            return theController
        }

        else{
            let theOtherOne  =  UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "screen2") as! MyPageViewController
            theOtherOne.page = theIndex
            return theOtherOne
        }
    }
}

//set up the after view
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {

    let theController = viewController as! MyPageViewController
    let theIndex = theController.page + 1
    if(theIndex >= thePack.count){
        return nil
    }
    else{
        if thePack[theIndex].article != ""{
            let theController =  UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "screen1") as? MyPageViewController
            theController.page = theIndex
            return theController
        }

        else{
            let theOtherOne  =  UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "screen2") as! MyPageViewController
            theOtherOne.page = theIndex
            return theOtherOne
        }
    }
}

And in the end one small advice from my side, be careful with the "custom" controllers from Apple, most of the are really crapy and hard to customise, in this category are the following: UIPageViewController , UITableViewController & UISplitViewController . In my opinion Apple should do a better job in prototyping these controllers to help the developers more, but in the end that's only my opinion

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM