Search code examples
iosswiftuitabbarcontrolleruipageviewcontroller

turn page programmatically in UIPageViewController from another tab in UITabBarController


I have a UITabBarController as root view controller.

In this UITabBarController, I have 2 tabs: tabA and tabB.

tabA is a general view controller, and tabB is a viewController with a Container View in which a pageViewcontroller C is embeded.

Now there is a button in tabA, I want to realize the effect that when I click this button, it will jump to tabB and show the second page in C, everytime when click the button, it will call the function:

func swipeToIndex(ToIndex: Int, completion: (()->Void)? = nil) {
    if self.currentPageIndex > 2 {
        return
    }
    if ToIndex < self.currentPageIndex {
        let toViewController = self.orderedViewControllers[ToIndex]
        self.setViewControllers([toViewController], direction: .reverse, animated: true, completion: {finish in
            self.currentPageIndex = ToIndex
            completion?()
        })
    }
    else if ToIndex > self.currentPageIndex {
        let toViewController = self.orderedViewControllers[ToIndex]
        self.setViewControllers([toViewController], direction: .forward, animated: true, completion: {finish in
            self.currentPageIndex = ToIndex
            completion?()
        })
    }
}

I can only realize it from the second time that I click the button. And the first time, it goes to the first page in C. I found it's something to do with the viewDidLoad(). when it calls the function swipeToIndex for the first time after

self.setViewControllers([toViewController], direction: .forward, animated: true, completion: {finish in self.currentPageIndex = ToIndex completion?() }) it will call viewDidLoad, inside there sets the viewcontroller again like following:

if let firstViewController = orderedViewControllers.first {
        setViewControllers([firstViewController],
                           direction: .forward,
                           animated: true,
                           completion: nil)
    } 

I have no clue how to avoid this when the first time call swipeToIndex


Solution

  • You will need to forward message a bit smarter and check if views have already been loaded.

    In your page controller you should check if a view is loaded:

    func swipeToIndex(ToIndex: Int, completion: (()->Void)? = nil) {
        guard isViewLoaded else {
            self.pageToSwipeTo = ToIndex
            return
        }
    

    So you need to add

    var pageToSwipeTo: Int? = nil
    

    Then in viewDidLoad at the end try

    if let pageToSwipeTo = pageToSwipeTo {
        self.pageToSwipeTo = nil
        self. swipeToIndex(pageToSwipeTo)
    }
    

    This is assuming the page view controller does already exist in your situation. This might actually not be true due to your hierarchy so you might need to forward the message even through the tab bar view controller... But try this procedure first.