0

按照这个答案,我设法将半模态呈现添加ViewControllerBViewControllerA. 但是,在示例中,ViewControllerA只是一个红色视图。我想将它连接到 IB 以便对其进行自定义。我尝试在类的 IB 中创建一个视图控制器ViewControllerB并将其视图之一连接到,@IBOutlet var menuView: UIView!而不是以menuView编程方式创建(如示例中所示)。但是,在作为子视图nil添加menuView到视图时发现。任何帮助都会很棒。谢谢!

4

1 回答 1

0

几点观察:

  1. 在那个例子中,有一行说:

    let vc = ViewControllerB()
    

    您可以在 NIB 中定义此视图控制器的视图,这样可以正常工作。但是,如果您使用的是故事板,请将其替换为...

    let vc = storyboard!.instantiateViewController(withIdentifier: “identifier")
    

    ...identifier您在 IB 的“身份检查器”中为该场景提供的作为“故事板 ID”的字符串在哪里。

  2. 如果这是由按钮或类似的东西触发的,您也可以gotoVCB在该示例中删除它,然后像往常一样在 IB 中进行模态演示(例如control- 从按钮拖动到下一个场景)并选择“以模态方式呈现”。但是您必须确保配置了所有init方法,例如:

    class ViewControllerB: UIViewController {
    
        // used if you use NIBs or just call `init()`
    
        override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
            super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
            configure()
        }
    
        // used if you use storyboards
    
        required init?(coder aDecoder: NSCoder) {
            super.init(coder: aDecoder)
            configure()
        }
    
        private func configure() {
            modalPresentationStyle = .custom
            transitioningDelegate = self
        }
    
        ...
    }
    
  3. 与直接问题无关,我可能建议将该答案的代码拆分为单独的对象,以防止视图控制器“膨胀”,更好地分离过渡委托对象、动画控制器等之间的职责。

    例如,也许:

    class ViewControllerB: UIViewController {
    
        let customTransitioningDelegate = PopUpMenuTransitioningDelegate()
    
        override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
            super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
            configure()
        }
    
        required init?(coder aDecoder: NSCoder) {
            super.init(coder: aDecoder)
            configure()
        }
    
        func configure() {
            modalPresentationStyle = .custom
            transitioningDelegate = customTransitioningDelegate
        }
    
    }
    

    class PopUpMenuTransitioningDelegate: NSObject, UIViewControllerTransitioningDelegate {
        func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
            return PopUpMenuAnimationController(transitionType: .presenting)
        }
    
        func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
            return PopUpMenuAnimationController(transitionType: .dismissing)
        }
    }
    

    class PopUpMenuAnimationController: NSObject, UIViewControllerAnimatedTransitioning {
        enum TransitionType {
            case presenting
            case dismissing
        }
    
        let transitionType: TransitionType
    
        init(transitionType: TransitionType) {
            self.transitionType = transitionType
            super.init()
        }
    
        func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
            return 1
        }
    
        func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
            let containerView = transitionContext.containerView
            guard let toVC = transitionContext.viewController(forKey: .to),
                let fromVC = transitionContext.viewController(forKey: .from) else { return }
    
            switch transitionType {
            case .presenting:
                containerView.addSubview(toVC.view)
    
                var rect = fromVC.view.bounds
                let menuHeight = fromVC.view.bounds.height / 2
                rect.origin.y += fromVC.view.bounds.height
                rect.size.height = menuHeight
                toVC.view.frame = rect
                toVC.view.alpha = 0
    
                UIView.animate(withDuration: 0.4, delay: 0, options: [.curveEaseOut], animations: {
                    rect.origin.y = menuHeight
                    toVC.view.frame = rect
                    toVC.view.alpha = 1
                }, completion: { _ in
                    transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
                })
    
            case .dismissing:
                UIView.animate(withDuration: 0.4, delay: 0, options: [.curveEaseOut], animations: {
                    var rect = fromVC.view.frame
                    rect.origin.y = toVC.view.bounds.height
                    fromVC.view.frame = rect
                    fromVC.view.alpha = 0
                }, completion: { _ in
                    transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
                })
            }
        }
    }
    

    这将转换委托和动画控制器与视图控制器分离,并允许您在需要时将其与其他视图控制器一起使用。

    请注意,我对 to 的参数也更加小心completeTransition。一旦开始使用交互式过渡,您可能会支持可取消的过渡。

于 2019-03-02T23:48:50.020 回答