Search code examples
iosswiftswiftuiuikit

UIAnimatedNavigationTransition with UIKit and SwiftUI


When creating an animated transition in an iOS application with UIKit, we typically use UIAnimatedNavigationTransition between two view controllers. However, a new business requirement necessitates replacing one of the view controllers with a SwiftUI view. How can we make the animated navigation transition work between a SwiftUI view and a UIKit view controller? Is there a way to achieve this?

Additionally, is there any documentation that explains how UIHostingController was created, not just how to implement it? Understanding its creation might help devise a workaround, but I haven't been able to find any resources on this.


Solution

  • you need to create a Animator & Transition Delegate

        import UIKit
    
        class Animator: NSObject, UIViewControllerAnimatedTransitioning {
    
           func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
            return 0.5
           }
    
           func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
            guard let fromVC = transitionContext.viewController(forKey: .from),
                  let toVC = transitionContext.viewController(forKey: .to) else {
                return
            }
    
            let containerView = transitionContext.containerView
    
            containerView.addSubview(toVC.view)
            toVC.view.frame = fromVC.view.frame
            toVC.view.alpha = 0.0
    
            UIView.animate(withDuration: transitionDuration(using: transitionContext), animations: {
                toVC.view.alpha = 1.0
            }) { finished in
                fromVC.view.removeFromSuperview()
                transitionContext.completeTransition(finished)
            }
           }
    }
    

    import UIKit
    
    class TransitioningDelegate: NSObject, UIViewControllerTransitioningDelegate {
        func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
            return Animator()
        }
    
        func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
            return Animator()
        }
    }
    

    then apply transition delegate to user hosting view controller in your view controller file on button action

    //MARK: - Properties
    let transitionDelegate = TransitioningDelegate()
    
    //MARK: - Button Action
    @objc func showSwiftUIView() {
        let swiftUIView = SwiftUIView()
        let hostingController = UIHostingController(rootView: swiftUIView)
        hostingController.modalPresentationStyle = .fullScreen
        hostingController.transitioningDelegate = transitionDelegate
        present(hostingController, animated: true, completion: nil)
    }