簡體   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