繁体   English   中英

对于iOS8中的自定义容器视图控制器,transitionCoordinator返回nil

[英]transitionCoordinator return nil for custom container view controller in iOS8

当在子vc上引用transitionCoordinator时,它曾经在iOS7中的自定义容器类上调用transitionCoordinator ,但在iOS8中并非如此。 现在它返回nil,我不知道应该怎么做才能使它工作。

我猜想它与iOS8中引入的UIPresentationController有关,但是找不到自定义容器视图控制器的正确实现。

正如Matt在上一个SO问题中所说:

因此,由于在允许您为内置父视图控制器编写自定义过渡动画的情况下,您甚至无法获得过渡协调器,因此很显然,在您尝试获得一个过渡协调器的情况下,你自己的父视图控制器是否为零

但是,根据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()
    }
}

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM