3

transitionCoordinator子 vc を参照する場合transitionCoordinator、iOS7 ではカスタム コンテナ クラスで呼び出されていましたが、iOS8 ではそうではありませんでした。今ではnilが返され、これを機能させるために何を変更すればよいかわかりません。

iOS8で導入​​されたUIPresentationControllerについてだと思いますが、カスタムコンテナView Controllerの適切な実装が見つかりません。

4

1 に答える 1

1

マットがこの前のSO の質問で言ったように:

したがって、組み込みの親ビュー コントローラー用のカスタム遷移アニメーションを作成できる状況では遷移コーディネーターを取得することさえできないため、明らかに、しようとしている状況で遷移コーディネーターを取得する可能性は低くなります。あなた自身の親View Controllerはゼロですか

しかし、transitionCoordinatorによると、オーバーライドが許可されています。

コンテナ ビュー コントローラはこのメソッドをオーバーライドできますが、ほとんどの場合、オーバーライドする必要はありません。このメソッドをオーバーライドする場合は、最初に super を呼び出して、返す適切な遷移コーディネーターがあるかどうかを確認し、ある場合はそれを返します。

そのため、自分の VC コンテナー用に独自のコーディネーターを作成しようとします。a を使用し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()
    }
}

もちろん、一部のエッジ ケースは処理されません。これは本当に基本的な例です。

于 2019-05-24T17:08:15.003 に答える