ios - UIView.animateWithDuration 的交互式过渡完成块从未在 animateTransition 内部调用

Posted

技术标签:

【中文标题】ios - UIView.animateWithDuration 的交互式过渡完成块从未在 animateTransition 内部调用【英文标题】:ios - interactive transition completion block for UIView.animateWithDuration never called inside animateTransition 【发布时间】:2016-07-03 22:36:42 【问题描述】:

我使用带有平移手势识别器的自定义交互式弹出过渡。我有 UIPercentDrivenInteractiveTransition 的子类来处理用户操作:

class InteractiveTransitionManager: UIPercentDrivenInteractiveTransition 

  var viewController: UIViewController?
  var interactive: Bool = false

  var popInProgress = false
  var startX: CGFloat = 0

  init(viewController: UIViewController) 
    super.init()
    self.viewController = viewController
    self.viewController?.view.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: "handlePan:"))
  

  func handlePan(pan: UIPanGestureRecognizer) 
    if pan.velocityInView(pan.view!.superview!).x > 0 && !popInProgress 
      popInProgress = true
      interactive = true
      startX = pan.locationInView(pan.view!.superview!).x
      viewController?.navigationController?.popViewControllerAnimated(true)
      return
    
    let curX = pan.locationInView(pan.view!.superview!).x
    let progress: CGFloat = max(0, curX - startX) / pan.view!.frame.width
    if pan.state == .Changed 
      updateInteractiveTransition(progress)
     else if pan.state == .Ended || pan.state == .Cancelled 
      if progress > 0.5 
        finishInteractiveTransition()
       else 
        cancelInteractiveTransition()
      
      popInProgress = false
      interactive = false
    
  


我有用于过渡动画的 InteractivePopTr​​ansition 类:

class InteractivePopTransition: NSObject, UIViewControllerAnimatedTransitioning 

func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval 
    return 0.3


func animateTransition(transitionContext: UIViewControllerContextTransitioning) 
    let fromVC = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey)!
    let toVC = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey)!
    let fromView = transitionContext.viewForKey(UITransitionContextFromViewKey)!
    let toView = transitionContext.viewForKey(UITransitionContextToViewKey)!
    let containterView = transitionContext.containerView()

    let targetFrame = transitionContext.finalFrameForViewController(toVC)

    toView.frame = CGRect(x: -targetFrame.size.width, y: targetFrame.origin.y, width: targetFrame.width, height: targetFrame.height)
    containterView?.insertSubview(toView, belowSubview: fromView)

    UIView.animateWithDuration(transitionDuration(transitionContext), animations: 
        toView.frame = targetFrame
        fromView.frame.origin.x = CGRectGetMaxX(targetFrame)
        , completion:  b in
            transitionContext.completeTransition(!transitionContext.transitionWasCancelled())
    )



我有一个问题,UIView.animateWithDuration 中的完成块有时没有被调用。为什么会发生这种情况以及如何解决?

【问题讨论】:

【参考方案1】:

animateTransition(transitionContext:) 被调用并且用户交互不是交互的(如程序化动画触发器)时,系统似乎存在时间问题并且UIView.animateWithDurationcompletion 没有被调用,就像你一样描述。

我在工作中遇到了这种情况,我能够通过在调用 UIView.animateWithDuration(...) 之前从 animateTransition(transitionContext:) 内显式调用 UIPercentDrivenInteractiveTransition 对象上的 finishInteractiveTransition 来解决此问题。

对于我的情况,这是一个简单的解决方案,因为我的 UIViewControllerAnimatedTransitioning 对象有一个 UIPercentDrivenInteractiveTransition 子类的实例,并且我公开了一个 interactionInProgress 属性来确定我应该何时显式调用 finishInteractiveTransition

如果您在交互式转换对象上显式调用finishInteractiveTransition,则会调用完成块。

class InteractivePopTransition: NSObject, UIViewControllerAnimatedTransitioning 
  private var interactiveTransitionManager: InteractiveTransitionManager
  ...
  func animateTransition(transitionContext: UIViewControllerContextTransitioning) 
    ...
    if !interactiveTransitionManager.isInProgress 
      // Weird state where system is telling you to animate a transition, but there
      // is no interactive transition occurring. Manually finish the non-existant
      // interactive transition so system will call other animation callbacks
      // appropriately to complete the entire transition
      interactiveTransitionManager.finish()
    
    UIView.animateWithDuration(...)
    

另一种解决方案是将UIView.animateWithDuration 放在一个调度异步块中,并有一小段延迟。

【讨论】:

以上是关于ios - UIView.animateWithDuration 的交互式过渡完成块从未在 animateTransition 内部调用的主要内容,如果未能解决你的问题,请参考以下文章

IO复用阻塞IO非阻塞IO同步IO异步IO

四种IO模型‘阻塞IO/非阻塞IO/信号驱动IO/异步IO‘

5种IO模型阻塞IO和非阻塞IO同步IO和异步IO

网络IO模型:同步IO和异步IO,阻塞IO和非阻塞IO

同步IO异步IO阻塞IO非阻塞IO之间的联系与区别

同步IO异步IO阻塞IO非阻塞IO之间的联系与区别