SwiftyJD SwiftyJD - 5 months ago 36
Swift Question

How to create a custom "flip horizontally" push segue like the one that's used for modal segues?

I'm trying to achieve something similar to this:

flip

but with a push segue inside a navigation controller. Is there a way to accomplish this?

Answer

I have done this several month ago.
1.Customize your transition. For example this is Push(so as Pop):

class BWFlipTransionPush: NSObject, UIViewControllerAnimatedTransitioning {

    func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval {
        return 0.5
    }

    func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
        let fromVC = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey) 
        let toVC = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey)! // as! UBPasswordLoginViewController
        let container = transitionContext.containerView()
        container!.addSubview(toVC.view)
        container!.bringSubviewToFront(fromVC!.view)

        //改变m34
        var transfrom = CATransform3DIdentity
        transfrom.m34 = -0.002
        container!.layer.sublayerTransform = transfrom

        //设置anrchPoint 和 position
        let initalFrame = transitionContext.initialFrameForViewController(fromVC!)
        toVC.view.frame = initalFrame
        fromVC!.view.frame = initalFrame
        toVC.view.layer.transform = CATransform3DMakeRotation(CGFloat(M_PI_2), 0, 1, 0)



        //动画
        UIView.animateWithDuration(transitionDuration(transitionContext), delay: 0, options: UIViewAnimationOptions.CurveEaseOut, animations: { () -> Void in
                fromVC!.view.layer.transform = CATransform3DMakeRotation(CGFloat(-M_PI_2), 0, 1, 0)
            }) { (finished: Bool) -> Void in
                container?.bringSubviewToFront(toVC.view)
                UIView.animateWithDuration(self.transitionDuration(transitionContext), delay: 0, options: UIViewAnimationOptions.CurveEaseOut, animations: { () -> Void in
                    toVC.view.layer.transform = CATransform3DIdentity
                }) { (finished: Bool) -> Void in

                    fromVC!.view.layer.transform = CATransform3DIdentity
                    transitionContext.completeTransition(!transitionContext.transitionWasCancelled())
                }

        }
    }
}

2.Set delegate for your navigation controller like this:

  override func viewDidLoad() {
        super.viewDidLoad()
        navigationController?.delegate = self
    }

3.Implement delegate function:

func navigationController(navigationController: UINavigationController, animationControllerForOperation operation: UINavigationControllerOperation, fromViewController fromVC: UIViewController, toViewController toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
    switch operation {
    case .Pop:
        return nil // you should return customized pop
    case .Push:
        return BWFlipTransionPush()
    default:
        return nil
    }
}

Update
Here is flip pop:

class BWFlipTransionPop: NSObject, UIViewControllerAnimatedTransitioning {

    func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval {
        return 0.5
    }

    func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
        let fromVC = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey)! // as! UBPasswordLoginViewController
        let toVC = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey)
        let container = transitionContext.containerView()
        container!.addSubview(toVC!.view)

        //改变m34
        var transfrom = CATransform3DIdentity
        transfrom.m34 = -0.002
        container!.layer.sublayerTransform = transfrom

        //设置anrchPoint 和 position
        let initalFrame = transitionContext.initialFrameForViewController(fromVC)
        toVC!.view.frame = initalFrame
        toVC!.view.layer.transform = CATransform3DMakeRotation(CGFloat(-M_PI_2), 0, 1, 0)


        //动画
        UIView.animateWithDuration(transitionDuration(transitionContext), delay: 0, options: UIViewAnimationOptions.CurveEaseOut, animations: { () -> Void in
            fromVC.view.layer.transform = CATransform3DMakeRotation(CGFloat(M_PI_2), 0, 1, 0)
        }) { (finished: Bool) -> Void in
            container?.bringSubviewToFront(toVC!.view)
            UIView.animateWithDuration(self.transitionDuration(transitionContext), delay: 0, options: UIViewAnimationOptions.CurveEaseOut, animations: { () -> Void in
                toVC!.view.layer.transform = CATransform3DIdentity
            }) { (finished: Bool) -> Void in


                fromVC.view.layer.transform = CATransform3DIdentity
                transitionContext.completeTransition(!transitionContext.transitionWasCancelled())
            }

        }

    }
}
Comments