Charles Panel
Charles Panel

Reputation: 255

Swift: how can I keep an embedded navigation controller after a custom segue?

I am trying to set up a custom segue from a view controller that is embedded in a navigation controller. When I use a show segue, everything is fine, the navigation bar remains as expected. However, when I try to use a custom segue class, the navigation bar disappears. After checking, the navigation controller is absent from the post-custom segue view controller. So it seems the problem comes from using a custom segue: how can I stay within the navigation controller with a custom segue? Here is my custom segue code, which purpose is to make the segue have a slide effect from top to bottom:

class FirstCustomSegue: UIStoryboardSegue {
override func perform() {
    var firstVCView = self.sourceViewController.view as UIView!
    var secondVCView = self.destinationViewController.view as UIView!

    // Get the screen width and height.
    let screenWidth = UIScreen.mainScreen().bounds.size.width
    let screenHeight = UIScreen.mainScreen().bounds.size.height

    // Specify the initial position of the destination view.
    secondVCView.frame = CGRectMake(0.0, -screenHeight, screenWidth, screenHeight)

    // Access the app's key window and insert the destination view above the current (source) one.
    let window = UIApplication.sharedApplication().keyWindow
    window?.insertSubview(secondVCView, aboveSubview: firstVCView)

    // Animate the transition.
    UIView.animateWithDuration(1, animations: { () -> Void in
        firstVCView.frame = CGRectOffset(firstVCView.frame, 0.0, screenHeight)
        secondVCView.frame = CGRectOffset(secondVCView.frame, 0.0, screenHeight)

        }) { (Finished) -> Void in
            self.sourceViewController.presentViewController(self.destinationViewController as! UIViewController,
                animated: false,
                completion: nil)
    }

}

}

Upvotes: 1

Views: 417

Answers (1)

emrys57
emrys57

Reputation: 6806

I think that for a custom segue, you have to execute a navigationController.pushViewController() operation to make the new VC appear on the old NC stack. I can't see a way to make that happen with a custom segue. However, I do see a way to make it look like it happens:

class FirstCustomSegue: UIStoryboardSegue {
override func perform() {
    let firstVCView = self.sourceViewController.view as UIView!
    let secondVCView = self.destinationViewController.view as UIView!

    // Get the screen width and height.
    let screenWidth = UIScreen.mainScreen().bounds.size.width
    let screenHeight = UIScreen.mainScreen().bounds.size.height

    // Specify the initial position of the destination view.
    secondVCView.frame = CGRectMake(0.0, -screenHeight, screenWidth, screenHeight)

    // make a UIView which looks like the sourceViewController's view, 
    // and add it to the destinationViewcontrollers's view, 
    // in the right place so it looks as though it does not move
    let v1 = firstVCView.snapshotViewAfterScreenUpdates(false)
    v1.frame = CGRectMake(0, screenHeight, screenWidth, screenHeight)
    secondVCView.addSubview(v1)

    // push the destination VC without animation
    // but it looks the same as the first so it seems as though nothing has happened.
    self.sourceViewController.navigationController?.pushViewController(self.destinationViewController, animated: false)
    // Animate the transition.
    UIView.animateWithDuration(1, animations: { () -> Void in
            secondVCView.frame = CGRectOffset(secondVCView.frame, 0.0, screenHeight)
        }) { (Finished) -> Void in
            v1.removeFromSuperview()
        }
    }
}

That does the pushViewController without an animation, then makes it look like it is animated by putting a snapshot of the source view temporarily onto the second view. It looks OK on my iPad.

Upvotes: 1

Related Questions