View being blocked by UITransitionView after being presented

后端 未结 6 707
心在旅途
心在旅途 2020-12-28 16:07

I have a side navigation controller and present it via a UIButton. When I make this NC the root view controller directly by [self presentviewcontroller: NC animated: Y

6条回答
  •  青春惊慌失措
    2020-12-28 16:28

    In my situation I needed a halfSize view controller. I followed this answer which worked great until I realized I needed to still be able to interact with the presenting vc (the vc behind the halfSizeVC).

    The key is that you have to set both of these frames with the same CGRect values:

    halfSizeVC.frame = CGRect(x: 0, y: UIScreen.main.bounds.height / 2, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)

    containerView = CGRect(x: 0, y: UIScreen.main.bounds.height / 2, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)

    Here is the code to go from ViewController to HalfSizeController and make HalfSizeController 1/2 the screen size. Even with halfSizeVC on screen you will still be able to interact with the top half of the vc behind it.

    You also have to make a PassthroughView class if you want to be able to touch something inside the halfSizeVC. I included it at the bottom.

    The presenting vc is white with a purple button at the bottom. Tapping the purple button will bring up the red halfSizeVC.

    vc/presentingVC:

    import UIKit
    
    class ViewController: UIViewController {
    
        lazy var purpleButton: UIButton = {
            let button = UIButton(type: .system)
            button.translatesAutoresizingMaskIntoConstraints = false
            button.setTitle("Tap to Present HalfSizeVC", for: .normal)
            button.setTitleColor(UIColor.white, for: .normal)
            button.backgroundColor = UIColor.systemPurple
            button.addTarget(self, action: #selector(purpleButtonPressed), for: .touchUpInside)
            button.layer.cornerRadius = 7
            button.layer.masksToBounds = true
            return button
        }()
    
        var halfSizeVC: HalfSizeController?
    
        override func viewDidLoad() {
            super.viewDidLoad()
            view.backgroundColor = .white
    
            // tap gesture on vc will dismiss HalfSizeVC
            let tapGesture = UITapGestureRecognizer(target: self, action: #selector(dismissHalfSizeVC))
            view.addGestureRecognizer(tapGesture)
        }
    
    
        // tapping the purple button presents HalfSizeVC
        @objc func purpleButtonPressed() {
    
            halfSizeVC = HalfSizeController()
    
            // *** IMPORTANT ***
            halfSizeVC!.view.frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height / 2)
    
            halfSizeVC!.modalPresentationStyle = .custom
    
            present(halfSizeVC!, animated: true, completion: nil)
        }
    
        // dismiss HalfSizeVC by tapping anywhere on the white background
        @objc func dismissHalfSizeVC() {
    
            halfSizeVC?.dismissVC()
        }
    }
    

    halfSizeVC/presentedVC

    import UIKit
    
    class HalfSizeController: UIViewController {
    
        init() {
            super.init(nibName: nil, bundle: nil)
            modalPresentationStyle = .custom
            transitioningDelegate = self
        }
    
        required init?(coder aDecoder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
    
        lazy var topHalfDummyView: PassthroughView = {
            let view = PassthroughView()
            view.translatesAutoresizingMaskIntoConstraints = false
            view.backgroundColor = .clear
            view.isUserInteractionEnabled = true
            return view
        }()
    
        var isPresenting = false
        let halfScreenHeight = UIScreen.main.bounds.height / 2
    
        override func viewDidLoad() {
            super.viewDidLoad()
            view.backgroundColor = .red
    
            setAnchors()
        }
    
        private func setAnchors() {
        
            view.addSubview(topHalfDummyView)
            topHalfDummyView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
            topHalfDummyView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
            topHalfDummyView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
            topHalfDummyView.heightAnchor.constraint(equalToConstant: halfScreenHeight).isActive = true
        }
    
        public func dismissVC() {
            dismiss(animated: true, completion: nil)
        }
    }
    
    extension HalfSizeController: UIViewControllerTransitioningDelegate, UIViewControllerAnimatedTransitioning {
    
        func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
            return self
        }
    
        func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
            return self
        }
    
        func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
            return 1
        }
    
        func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
    
            let containerView = transitionContext.containerView
    
            // *** IMPORTANT ***
            containerView.frame = CGRect(x: 0, y: halfScreenHeight, width: UIScreen.main.bounds.width, height: halfScreenHeight)
    
            let toViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to)
            guard let toVC = toViewController else { return }
            isPresenting = !isPresenting
    
            if isPresenting == true {
                containerView.addSubview(toVC.view)
    
                topHalfDummyView.frame.origin.y += halfScreenHeight
    
                UIView.animate(withDuration: 0.4, delay: 0, options: [.curveEaseOut], animations: {
    
                    self.topHalfDummyView.frame.origin.y -= self.halfScreenHeight
    
                }, completion: { (finished) in
                    transitionContext.completeTransition(true)
                })
    
            } else {
                UIView.animate(withDuration: 0.4, delay: 0, options: [.curveEaseOut], animations: {
                
                }, completion: { (finished) in
                    self.topHalfDummyView.frame.origin.y += self.halfScreenHeight
                    transitionContext.completeTransition(true)
                })
            }
        }
    }
    

    PassthroughView needed for the topHalfDummyView in HalfSizeVC

    import UIKit
    
    class PassthroughView: UIView {
        
        override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
            print("Passing all touches to the next view (if any), in the view stack.")
            return false
        }
    }
    

    Before purple button is pressed:

    After purple button is pressed:

    If you press the white background the red color will get dismissed

    You can just c+p all 3 files and run your project

提交回复
热议问题