NavigationController由一个按钮调用,因此在呈现时没有交互式转换.它可以通过按钮或UIPanGestureRecognizer来解除,因此它可以被交互或不被解雇.
我有一个名为TransitionManager的对象,用于转换,UIPercentDrivenInteractiveTransition的子类.
下面的代码的问题是从不调用两个委托方法interactionControllerFor ….
此外,当我按下按钮或swip(UIPanGestureRecognizer)时,模态segue的基本动画就完成了.所以两个委托方法animationControllerFor …也不起作用.
有任何想法吗 ?谢谢
ViewController.swift
let transitionManager = TransitionManager() override func viewDidLoad() { super.viewDidLoad() self.transitioningDelegate = transitionManager } override func prepareForSegue(segue: UIStoryboardSegue,sender: AnyObject?) { let dest = segue.destinationViewController as UIViewController dest.transitioningDelegate = transitionManager dest.modalPresentationStyle = .Custom }
TransitionManager.swift
class TransitionPushManager: UIPercentDrivenInteractiveTransition,UINavigationControllerDelegate,UIViewControllerTransitioningDelegate { @IBOutlet var navigationController: UINavigationController! var animation : Animator! // Implement UIViewControllerAnimatedTransitioning protocol override func awakeFromNib() { var panGesture = UIPanGestureRecognizer(target: self,action: "gestureHandler:") navigationController.view.addGestureRecognizer(panGesture) animation = Animator() } func gestureHandler(pan : UIPanGestureRecognizer) { switch pan.state { case .Began : interactive = true navigationController.presentingViewController?.dismissViewControllerAnimated(true,completion:nil) case .Changed : ... default : ... interactive = false } } func animationControllerForPresentedController(presented: UIViewController,presentingController presenting: UIViewController,sourceController source: UIViewController) -> UIViewControllerAnimatedTransitioning? { return animation } func animationControllerFordismissedController(dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? { return animation } func interactionControllerForPresentation(animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? { return nil } func interactionControllerFordismissal(animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? { return self.interactive ? self : nil }
Main.storyboard
> ViewController上的按钮触发了一个模态segue来呈现NavigationController
> NavigationController的委托出口链接到TransitionManager类的对象
> NavigationController在TransitionManager类中由属性“navigationController”引用
解决方法
让我们想象你的根场景(“Root”)呈现导航控制器场景(“Nav”),然后从场景A推送到B到C,例如,我想象一个这样的对象模型,导航控制器只会拥有自己的动画控制器,交互控制器和手势识别器:
这是您在考虑(a)“root”呈现“nav”时的自定义转换(非交互式)时所需要的; (b)当“nav”自行解散以返回“根”时的自定义转换(交互与否).所以,我将导航控制器子类化为:
>在其视图中添加手势识别器;
>设置transitioningDelegate以在从根场景转换到导航控制器场景(并返回)时生成自定义动画:
> transitioningDelegate还将返回交互控制器(仅在手势识别器正在进行时才存在),如果您在手势的上下文之外解除,则在手势和非交互式转换期间产生交互式转换.
在Swift 3中,它看起来像:
import UIKit import UIKit.UIGestureRecognizerSubclass class CustomNavigationController: UINavigationController { public required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) configure() } override init(rootViewController: UIViewController) { super.init(rootViewController: rootViewController) configure() } private func configure() { transitioningDelegate = self // for presenting the original navigation controller } override func viewDidLoad() { super.viewDidLoad() delegate = self // for navigation controller custom transitions let left = UIScreenEdgePanGestureRecognizer(target: self,action: #selector(handleSwipeFromLeft(_:))) left.edges = .left view.addGestureRecognizer(left) } fileprivate var interactionController: UIPercentDrivenInteractiveTransition? func handleSwipeFromLeft(_ gesture: UIScreenEdgePanGestureRecognizer) { let percent = gesture.translation(in: gesture.view!).x / gesture.view!.bounds.size.width if gesture.state == .began { interactionController = UIPercentDrivenInteractiveTransition() if viewControllers.count > 1 { popViewController(animated: true) } else { dismiss(animated: true) } } else if gesture.state == .changed { interactionController?.update(percent) } else if gesture.state == .ended { if percent > 0.5 && gesture.state != .cancelled { interactionController?.finish() } else { interactionController?.cancel() } interactionController = nil } } } // MARK: - UINavigationControllerDelegate // // Use this for custom transitions as you push/pop between the varIoUs child view controllers // of the navigation controller. If you don't need a custom animation there,you can comment this // out. extension CustomNavigationController: UINavigationControllerDelegate { func navigationController(_ navigationController: UINavigationController,animationControllerFor operation: UINavigationControllerOperation,from fromVC: UIViewController,to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? { if operation == .push { return ForwardAnimator() } else if operation == .pop { return BackAnimator() } return nil } func navigationController(_ navigationController: UINavigationController,interactionControllerFor animationController: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? { return interactionController } } // MARK: - UIViewControllerTransitioningDelegate // // This is needed for the animation when we initially present the navigation controller. // If you're only looking for custom animations as you push/pop between the child view // controllers of the navigation controller,this is not needed. This is only for the // custom transition of the initial `present` and `dismiss` of the navigation controller // itself. extension CustomNavigationController: UIViewControllerTransitioningDelegate { func animationController(forPresented presented: UIViewController,presenting: UIViewController,source: UIViewController) -> UIViewControllerAnimatedTransitioning? { return ForwardAnimator() } func animationController(fordismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? { return BackAnimator() } func interactionControllerForPresentation(using animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? { return interactionController } func interactionControllerFordismissal(using animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? { return interactionController } func presentationController(forPresented presented: UIViewController,presenting: UIViewController?,source: UIViewController) -> UIPresentationController? { return PresentationController(presentedViewController: presented,presenting: presenting) } } // When doing custom `present`/`dismiss` that overlays the entire // screen,you generally want to remove the presenting view controller's // view from the view hierarchy. This presentation controller // subclass accomplishes that for us. class PresentationController: UIPresentationController { override var shouldRemovePresentersView: Bool { return true } } // You can do whatever you want in the animation; I'm just fading class ForwardAnimator : NSObject,UIViewControllerAnimatedTransitioning { func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { return 0.5 } func animateTransition(using context: UIViewControllerContextTransitioning) { let toView = context.viewController(forKey: .to)!.view! context.containerView.addSubview(toView) toView.alpha = 0.0 UIView.animate(withDuration: transitionDuration(using: context),animations: { toView.alpha = 1.0 },completion: { finished in context.completeTransition(!context.transitionWasCancelled) }) } } class BackAnimator : NSObject,UIViewControllerAnimatedTransitioning { func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { return 0.5 } func animateTransition(using context: UIViewControllerContextTransitioning) { let toView = context.viewController(forKey: .to)!.view! let fromView = context.viewController(forKey: .from)!.view! context.containerView.insertSubview(toView,belowSubview: fromView) UIView.animate(withDuration: transitionDuration(using: context),animations: { fromView.alpha = 0.0 },completion: { finished in context.completeTransition(!context.transitionWasCancelled) }) } }
因此,我可以将故事板中我的导航控制器的基类更改为此自定义子类,现在根场景可以只显示导航控制器(没有特殊的准备(对于:))并且一切正常.