Xcode 10:自定义动画过渡被困住

Sha*_*vim 3 custom-transition ios12 xcode10

我的应用程序有两个视图控制器(VC A和B)以及它们之间的自定义转换.

当在VC A上使用左向平移手势时,交互式动画过渡在模式上呈现VC B从A向右滑动(从右到左).要关闭VC B,用户可以:

  • 使用右向平移手势:将触发交互式转换,将VC B向右滑动并揭开VC A. VC B的位置由平移手势状态交互确定.交互由UIPercentDrivenInteractiveTransition对象"驱动" .
  • 使用VC B导航栏上的"关闭"按钮.这将触发自定义过渡(向右滑动)而不进行交互(仅动画).

问题是在Xcode 10 Seed(build 10A254a)+ iOS 12 Simulator(X或XR或XS)上进行测试我可以很容易地进入自定义转换永远不会完成且UI处于奇怪状态的状态:

  • UI卡在VC B上,没有手势或点击工作.
  • 该应用程序没有卡住 - 我可以看到conosle日志仍在滚动,netwrok活动正在运行(日志中没有错误)
  • 暂停应用程序处于这种卡住状态我可以看到com.apple.main-thread没有卡住.
  • 当我点击"调试视图层次结构"时,会发生一些奇怪的事情:在SIM屏幕上,我仍然可以看到VC B并禁用所有UI.在视图调试器主视图上 - 我可以看到VC A的子视图被绘制,就像转换完成一样.在视图调试器左侧树视图 - 我可以看到VC B视图层次结构.

此问题从未出现在任何先前版本的Xcode和/或iOS Xcode 10/iOS12之前.

这是animateTransition我的自定义方法UIViewControllerAnimatedTransitioning

func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {

    guard let fromVC = transitionContext.viewController(forKey: .from), let toVC = transitionContext.viewController(forKey: .to) else {
        transitionContext.completeTransition(false)
        return
    }

    let containterView = transitionContext.containerView
    containterView.insertSubview(toVC.view, belowSubview: fromVC.view)

    let bounds = fromVC.view.bounds
    var xOffsetMultiplier : CGFloat = 0.0
    var yOffsetMultiplier : CGFloat = 0.0

    switch direction {
    case .up:
        yOffsetMultiplier  = -1.0
    case .right:
        xOffsetMultiplier  = 1.0
    case .left:
        xOffsetMultiplier  = -1.0
    case .down:
        yOffsetMultiplier  = 1.0
    }

    print(xOffsetMultiplier,bounds.size.width,bounds.size.height )
    UIView.animate(withDuration: duration, animations: {
        print("animating...")
        //fromVC.navigationController?.navigationBar.alpha = 0.0
        fromVC.view.frame = fromVC.view.frame.offsetBy(dx: xOffsetMultiplier * bounds.size.width, dy: yOffsetMultiplier * bounds.size.height)
    }, completion: { finished in
        print("completed animation")
        transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
        //fromVC.navigationController?.navigationBar.alpha = 1.0
    })

}
Run Code Online (Sandbox Code Playgroud)

打印件只用于调试.

这是可以轻松重现问题的序列:

  1. 使用平移手势开始的B回到A,但从未完成它的互动过渡-这将调用cancel()上的UIPercentDrivenInteractiveTransition对象+我可以确认的动画完成.
  2. 点击"关闭"按钮调用非交互式过渡以解除B. B永远不会解散,自定义动画永远不会完成!

在设备上我根本无法重新创建此问题 - 并且所有转换都按预期工作.

小智 6

尝试wantsInteractiveStart = false在UIPercentDrivenInteractiveTransition中进行设置


Sha*_*vim 5

所以找到了为什么转换在 VC B 和 A 之间卡住的原因,但仍然没有真正理解 Xcode9/iOS11 和 Xcode10/iOS12 之间产生不同行为的不同之处。

为了保持简短:

  • 当使用平移手势启动交互式转换以关闭 VC 时,BI 分配一个UIPercentDrivenInteractiveTransition,调用dismiss(animated:completion:)VC 并根据平移进度更新它。在某些情况下,出锅时没有足够的遍历“地面”我的手势处理机认为过渡取消和调用cancel()的方法UIPercentDrivenInteractiveTransition
  • 在这样的取消之后,点击关闭按钮会启动一个新的dismiss(animated:completion:)但因为UIPercentDrivenInteractiveTransition仍然分配它由我的转换委托返回并且操作系统实际上尝试交互式解除虽然这不是意图。这是我的一个错误,因为在调用之后cancel我还应该确保转换委托在这种情况下不会尝试交互式转换(尽管在 Xcode9/iOS11 上它没有)。
  • 过渡“卡住”的原因是因为它是一个没有更新的交互式过渡(点击“关闭”时没有手势更新。我通过强制finish()错误分配的a来验证这一点,UIPercentDrivenInteractiveTransition以便它完成并且一切都恢复正常。

确保关闭转换是交互式的或不是基于用户交互的,尤其是在取消交互式之后,解决了问题。

我不明白的是为什么 Xcode/iOS 版本之间没有这种一致的行为。我以前从未在任何设备或模拟器上遇到过这个问题。自定义动画/过渡的处理方式有所不同 - Apple 文档中没有任何内容可以解释这一点 - 也许在过渡上下文的内部实现中。

从一个幼稚的“眼睛测试”来看,Xcode10 模拟器上的过渡动画的反应时间似乎比以前更慢,而且不如以前流畅,但仍然不能完全解释它。