Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When using a custom transition, why does the UIDropShadowView inset the presenting view controller?

Tags:

xcode

swift

I am writing a basic custom transition with swift. My issue is that the transition is insetting the presenting view controller with rounded corners for some reason. Why is this happening, and is it possible to disable it?

custom_transition

Presenting view controller:

final class ViewController: UIViewController {

    let card = UIView()

    override func viewDidLoad() {
        super.viewDidLoad()

        view.addSubview(card)
        card.heightAnchor == 200
        card.horizontalAnchors == view.horizontalAnchors + 24
        card.centerAnchors == view.centerAnchors

        card.backgroundColor = .black
        card.layer.cornerRadius = 8

        view.backgroundColor = .white

        card.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(presentView)))

    }

    @objc func presentView() {

        let detail = DetailViewController()
        detail.transitioningDelegate = self
        present(detail, animated: true, completion: nil)

    }
}

extension ViewController: UIViewControllerTransitioningDelegate {
    public func animationController(forPresented presented: UIViewController,
                                    presenting: UIViewController,
                                    source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        return CardModalPresentAnimator()
    }
}

Presented view controller:

final class DetailViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .red
    }
}

Custom Transition:

final class CardModalPresentAnimator: NSObject, UIViewControllerAnimatedTransitioning {

    func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
        return 0.4
    }

    func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {

        guard
            let fromVC = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from) as? ViewController,
            let toVC = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to) as? DetailViewController
            else { return }

        let containerView = transitionContext.containerView
        containerView.insertSubview(toVC.view, aboveSubview: fromVC.view)
        toVC.view.frame = fromVC.card.frame

        UIView.animate(withDuration: transitionDuration(using: transitionContext), animations: {
            // center the modal on the screen
            toVC.view.frame = UIScreen.main.bounds
        }, completion: { _ in
            transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
        })
    }
}
like image 890
thexande Avatar asked Sep 19 '25 20:09

thexande


1 Answers

In iOS 13, .automatic is the default modalPresentationStyle for UIViewController. For the standard modal presentation, use .fullScreen.

public enum UIModalPresentationStyle : Int {


    case fullScreen

    @available(iOS 3.2, *)
    case pageSheet

    @available(iOS 3.2, *)
    case formSheet

    @available(iOS 3.2, *)
    case currentContext

    @available(iOS 7.0, *)
    case custom

    @available(iOS 8.0, *)
    case overFullScreen

    @available(iOS 8.0, *)
    case overCurrentContext

    @available(iOS 8.0, *)
    case popover


    @available(iOS 7.0, *)
    case none

    @available(iOS 13.0, *)
    case automatic
}
like image 198
thexande Avatar answered Sep 23 '25 06:09

thexande