View being blocked by UITransitionView after being presented

后端 未结 6 675
心在旅途
心在旅途 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

    To get tap events through the UITransitionView, set the containerView's userInteractionEnabled to false. This is if you're doing a custom transition animation by using UIViewControllerAnimatedTransitioning.

    Example, in your animateTransition(_:):

    func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
    
        let containerView = transitionContext.containerView
        containerView.isUserInteractionEnabled = false
    
        ...
    }
    
    0 讨论(0)
  • 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

    0 讨论(0)
  • 2020-12-28 16:34

    I was facing the same issue, and this solved issue for me,

    navigationController.setNavigationBarHidden(true, animated: false)

    This worked for me as I am having custom view as navigation bar in view controllers.

    0 讨论(0)
  • 2020-12-28 16:34

    I had a similar issue where a UITransitionView kept blocking my views, preventing any user interaction.

    In my case this was due to an uncompleted custom animated UIViewController transition.

    I forgot to properly complete my transition with:

    TransitionContext.completeTransition(transitionContext.transitionWasCancelled)
    

    or

    TransitionContext.completeTransition(!transitionContext.transitionWasCancelled)
    

    In the

    func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {}
    

    from the UIViewControllerAnimatedTransitioning protocol

    0 讨论(0)
  • 2020-12-28 16:35

    I had the same issue but in a little different scenario, I ended up doing something very similar to find the view but instead of removing the view which can be more problematic I disabled the user interaction so any touch events just go throw it and any other objects can handle to user's interaction. In my case this was only present after updating the app to iOS 10, the same code running in iOS 9 didn't fall into this.

    0 讨论(0)
  • 2020-12-28 16:42

    Ive had this issue when I was setting accessibilityElements on a popover view controller. I fix it by removing assigning an array of elements.

    0 讨论(0)
提交回复
热议问题