transitionCoordinator在iOS8中为自定义容器视图控制器返回nil

时间:2014-12-24 15:04:43

标签: ios uicontainerview uipresentationcontroller transition-coordinator

在子vc上引用transitionCoordinator时,它曾经在iOS7中的自定义容器类上调用transitionCoordinator,但在iOS8中,情况并非如此。现在它返回零,我不知道应该改变什么来使这项工作。

我猜它是关于在iOS8中引入的UIPresentationController,但无法找到自定义容器视图控制器的正确实现。

1 个答案:

答案 0 :(得分:0)

如马特在之前的SO question中所说:

  

因此,由于您甚至无法在特定情况下获得过渡协调员   您可以在其中为   内置的父视图控制器,很明显您获得的机会   一种在您尝试做自己的父视图的情况下   控制器为零

但是,根据transitionCoordinator,允许对其进行覆盖:

  

容器视图控制器可以覆盖此方法,但在大多数情况下   应该不需要。如果您确实要重写此方法,请先调用super   看看是否有合适的过渡协调员返回,   然后,如果有的话,将其退回。

因此,我将尝试为自己的VC容器创建自己的协调器。如果您使用UIViewPropertyAnimator来操作VC容器的子级,则几乎是很简单的。

这里是一个例子:

class PropertyAnimatorTransitionCoordinator: NSObject, UIViewControllerTransitionCoordinator, UIViewControllerTransitionCoordinatorContext {

    private let parentView: UIView
    private let fromViewController: UIViewController?
    private let toViewController: UIViewController
    private let animator: UIViewPropertyAnimator

    // MARK: - Life Cycle

    init(parentView: UIView,
         fromViewController: UIViewController?,
         toViewController: UIViewController,
         animator: UIViewPropertyAnimator) {
        self.parentView = parentView
        self.fromViewController = fromViewController
        self.toViewController = toViewController
        self.animator = animator
    }

    // MARK: - UIViewControllerTransitionCoordinator

    func animate(alongsideTransition animation: ((UIViewControllerTransitionCoordinatorContext) -> Void)?,
                 completion: ((UIViewControllerTransitionCoordinatorContext) -> Void)? = nil) -> Bool {
        var isSuccessful = false
        if let animation = animation {
            animator.addCompletion { [weak self] _ in
                guard let context = self else { return }
                animation(context)
            }
            isSuccessful = true
        }
        if let completion = completion {
            animator.addCompletion { [weak self] _ in
                guard let context = self else { return }
                completion(context)
            }
            isSuccessful = true
        }
        return isSuccessful
    }

    func animateAlongsideTransition(in view: UIView?, animation: ((UIViewControllerTransitionCoordinatorContext) -> Void)?, completion: ((UIViewControllerTransitionCoordinatorContext) -> Void)? = nil) -> Bool {
        return animate(alongsideTransition: animation, completion: completion)
    }

    func notifyWhenInteractionEnds(_ handler: @escaping (UIViewControllerTransitionCoordinatorContext) -> Void) {
        animator.addCompletion { [weak self] _ in
            guard let context = self else { return }
            handler(context)
        }
    }

    func notifyWhenInteractionChanges(_ handler: @escaping (UIViewControllerTransitionCoordinatorContext) -> Void) {
        animator.addCompletion { [weak self] _ in
            guard let context = self else { return }
            handler(context)
        }
    }

    // MARK: - UIViewControllerTransitionCoordinatorContext

    var isAnimated: Bool {
        return true
    }

    var presentationStyle: UIModalPresentationStyle {
        return .none
    }

    var initiallyInteractive: Bool {
        return false
    }

    var isInterruptible: Bool {
        return animator.isInterruptible
    }

    var isInteractive: Bool {
        return animator.isUserInteractionEnabled
    }

    var isCancelled: Bool {
        return !animator.isRunning
    }

    var transitionDuration: TimeInterval {
        return animator.duration
    }

    var percentComplete: CGFloat {
        return animator.fractionComplete
    }

    var completionVelocity: CGFloat {
        return 0
    }

    var completionCurve: UIView.AnimationCurve {
        return animator.timingParameters?.cubicTimingParameters?.animationCurve ?? .linear
    }

    var targetTransform: CGAffineTransform {
        return .identity
    }

    var containerView: UIView {
        return parentView
    }

    func viewController(forKey key: UITransitionContextViewControllerKey) -> UIViewController? {
        switch key {
        case .from:
            return fromViewController
        case .to:
            return toViewController
        default:
            return nil
        }
    }

    func view(forKey key: UITransitionContextViewKey) -> UIView? {
        switch key {
        case .from:
            return fromViewController?.view
        case .to:
            return toViewController.view
        default:
            return nil
        }
    }
}

在我的自定义容器中,我将像这样使用它:

class CustomContainerViewController: UIViewController {

    private var customTransitionCoordinator: UIViewControllerTransitionCoordinator?

    override var transitionCoordinator: UIViewControllerTransitionCoordinator? {
        if let coordinator = super.transitionCoordinator {
            return coordinator
        }
        return customTransitionCoordinator
    }

    override var shouldAutomaticallyForwardAppearanceMethods: Bool {
        return false
    }

    func insertNewChild(_ viewController: UIViewController) {
        let animator = UIViewPropertyAnimator(duration: 0.3, curve: .easeInOut)
        customTransitionCoordinator = PropertyAnimatorTransitionCoordinator(
            parentView: view,
            fromViewController: nil,
            toViewController: viewController,
            animator: animator
        )
        animator.addCompletion { [weak self] _ in
            guard let parent = self else { return }
            viewController.didMove(toParent: parent)
            self?.customTransitionCoordinator = nil
        }
        addChild(viewController)
        viewController.beginAppearanceTransition(true, animated: true)
        view.addSubview(viewController.view)
        let target = view.bounds
        viewController.view.frame = target
        viewController.view.frame.origin.x = -target.width
        view.layoutIfNeeded()
        animator.addAnimations {
            viewController.view.frame = target
        }
        animator.addCompletion { [weak self] _ in
            guard let parent = self else { return }
            viewController.endAppearanceTransition()
            viewController.didMove(toParent: parent)
            self?.customTransitionCoordinator = nil
        }
        animator.startAnimation()
    }
}

当然,某些边缘情况没有处理。这是一个非常基本的例子。