永远不会调用交互式代理方法 [英] Interactive Delegate Methods Never Called

查看:152
本文介绍了永远不会调用交互式代理方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在ViewController(1)和NavigationViewController(2)之间进行交互式转换。

I want to make an interactive transition between a ViewController (1) and a NavigationViewController (2).

NavigationController由一个按钮调用,因此在呈现时没有交互式转换。它可以通过按钮或UIPanGestureRecognizer来解除,因此它可以被交互或不被解雇。

The NavigationController is called by a button, so there's no interactive transition when presenting. It can be dismissed by a button or a UIPanGestureRecognizer, so it can be dismissed interactively or not.

我有一个名为TransitionManager的对象,用于转换,UIPercentDrivenInteractiveTransition的子类。

I have an object named TransitionManager for the transition, subclass of UIPercentDrivenInteractiveTransition.

以下代码的问题是从不调用两个委托方法 interactionControllerFor ...

The problem with the code below is that the two delegate methods interactionControllerFor... are never called.

此外,当我按下按钮或swip(UIPanGestureRecognizer)时,模态segue的基本动画就完成了。所以两个委托方法 animationControllerFor ... 也不起作用。

Moreover, when I press the buttons or swip (UIPanGestureRecognizer), the basic animation of the modal segue is done. So the two delegate methods animationControllerFor... don't work either.

任何想法?谢谢

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



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

    Main.storyboard

    • The button on the ViewController triggered a modal segue to presenting the NavigationController

      NavigationController的委托出口链接到TransitionManager类的对象

      The NavigationController's delegate outlet is linked to an object of the TransitionManager class

      NavigationController在属性navigationController中引用了TransitionController

      The NavigationController is referenced in the TransitionManager class by the property "navigationController"

      推荐答案

      我认为关键问题是你正在配置 transitionDelegate in viewDidLoad 。在这个过程中,这通常太晚了。您应该在 init 导航控制器时执行此操作。

      I think the key problem is that you're configuring the transitionDelegate in viewDidLoad. That's often too late in the process. You should do it as you init the navigation controller.

      让我们想象您的根场景(Root)呈现导航控制器场景(导航),然后从场景A推送到B到C,例如,我想象一个像这样的对象模型,导航控制器将只拥有自己的动画控制器,交互控制器,和手势识别器:

      Let's imagine your root scene ("Root") that presents the navigation controller scene ("Nav"), that then pushes from scene A to B to C, for example, I'd imagine an object model like this, where the navigation controller would simply own its own animation controller, interaction controller, and gesture recognizer:

      当考虑到(a)root呈现nav时的自定义转换(非交互式)时,这就是你所需要的; (b)当nav自行解散以返回根时的自定义转换(交互与否)。所以,我将导航控制器子类化:

      This is all you need when considering (a) a custom transition (non-interactive) when "root" presents "nav"; and (b) a custom transition (interactive or not) when "nav" dismisses itself in order to return to the "root". So, I'd subclass the navigation controller which:


      • 在其视图中添加手势识别器;

      • adds a gesture recognizer to its view;

      设置 transitioningDelegate ,以便在从根场景转换到导航控制器场景(并返回)时生成自定义动画:

      sets the transitioningDelegate to yield the custom animation as you transition from the root scene to the navigation controller scene (and back):

      transitioningDelegate 还将返回交互控制器(只有在手势识别器处于此状态时才会存在)如果你在手势的上下文之外解散,则在手势和非交互式转换期间产生交互式转换。

      the transitioningDelegate will also return the interaction controller (which will only exist while the gesture recognizer is in progress), yielding interactive transition during gesture and non-interactive transition if you dismiss outside of the context of the gesture.

      在Swift 3中,它看起来像:

      In Swift 3, that looks like:

      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)
              })
          }
      }
      

      所以,我可以将故事板中我的导航控制器的基类更改为这个自定义子类,现在根场景可以只出现导航控制器(没有特殊的 prepare(for :)),一切正常。

      So, I can just change the base class of my navigation controller in the storyboard to be this custom subclass, and now the root scene can just present the navigation controller (with no special prepare(for:)) and everything just works.

      这篇关于永远不会调用交互式代理方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆