iOS Development

ios – Accessing SwiftUI subviews to animate in UiKit

Spread the love


I’m utilizing two UIHostingControllers with SwiftUI views, presenting one in every of them modally utilizing .current(...).
In my SwiftUI view hierarchy of each of the rootViews of the UIHostingControllers there may be one subview that I need to animate “into” one another, i.e. transition one body over the opposite when dismissing the modal viewcontroller.


Possibility 1: In pure SwiftUI, this might simply be accomplished utilizing matchedGeometryEffect, nonetheless this doesn’t work since they aren’t a part of the identical view, each have their very own UIHostingController that they’re a part of.

Possibility 2: In pure UiKit, this may very well be accomplished implementing a UIViewControllerAnimatedTransitioning and UIViewControllerTransitioningDelegate. Nevertheless, to be able to animate, one would wish the UIViews and their body and use one thing like UIView.animateKeyframes(...).

How can this be achieved in above described case? In my understanding one can not entry the subviews of a SwiftUI view utilizing one thing like view.subviews.... May I implement some kind of modifier so as to add to the related SwiftUI subviews to reveal them to UiKit? If that’s the case, how can this be accomplished?

How else can one implement customized transitions / animations between views inside completely different UIHostingControllers?


UIHostingControllers code:

class MyViewController: UIViewController, ViewController {
    
    weak var viewModel: MyViewModel!
    
    override func viewDidLoad() {
        tremendous.viewDidLoad()
        
        view.backgroundColor = UIColor(named: "background")
    }
    
    func setup() {
        let myView = MyView(viewModel: self.viewModel)
        let vc = UIHostingController(rootView: myView)
        addChild(vc)
        vc.view.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(vc.view)
        vc.didMove(toParent: self)

        NSLayoutConstraint.activate([
            vc.view.widthAnchor.constraint(equalTo: view.widthAnchor),
            vc.view.heightAnchor.constraint(equalTo: view.heightAnchor),
            vc.view.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            vc.view.centerYAnchor.constraint(equalTo: view.centerYAnchor)
        ])
    }
}

In another a part of the code I name:

viewController.modalPresentationStyle = .fullScreen
viewController.modalTransitionStyle = .crossDissolve
navigationController.current(viewController, animated: true)

And the unfinished code for the customized transition:

class ShrinkDismissAnimationController: NSObject, UIViewControllerAnimatedTransitioning {
    
    func transitionDuration(utilizing transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
        return 0.6
    }
    
    func animateTransition(utilizing transitionContext: UIViewControllerContextTransitioning) {
        guard let fromVC = transitionContext.viewController(forKey: .from),
              let toVC = transitionContext.viewController(forKey: .to),
              let fromVCStatusCapture = fromVC as? MyViewController,
              let imageView = fromVCStatusCapture.view.subviews.first(the place: { $0 is Picture }) // <- HERE! this does not work, how can I entry a SwiftUI subview ???
        else {
            return
        }
        // ...
        UIView.animateKeyframes(
            withDuration: period,
            delay: 0,
            choices: .calculationModeCubic,
            animations: {
        // ...
        })
     }
}

class ShrinkDismissTransition: NSObject, UIViewControllerTransitioningDelegate {
    func animationController(forDismissed dismissed: UIViewController)
    -> UIViewControllerAnimatedTransitioning? {
        guard let _ = dismissed as? MyViewController else {
            return nil
        }
        return ShrinkDismissAnimationController()
    }
}

Leave a Reply

Your email address will not be published. Required fields are marked *