transitionCoordinator
子 vc を参照する場合transitionCoordinator
、iOS7 ではカスタム コンテナ クラスで呼び出されていましたが、iOS8 ではそうではありませんでした。今ではnilが返され、これを機能させるために何を変更すればよいかわかりません。
iOS8で導入されたUIPresentationControllerについてだと思いますが、カスタムコンテナView Controllerの適切な実装が見つかりません。
transitionCoordinator
子 vc を参照する場合transitionCoordinator
、iOS7 ではカスタム コンテナ クラスで呼び出されていましたが、iOS8 ではそうではありませんでした。今ではnilが返され、これを機能させるために何を変更すればよいかわかりません。
iOS8で導入されたUIPresentationControllerについてだと思いますが、カスタムコンテナView Controllerの適切な実装が見つかりません。
マットがこの前の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()
}
}
もちろん、一部のエッジ ケースは処理されません。これは本当に基本的な例です。