3

我的应用程序有两个视图控制器(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 or XR or XS) 上进行测试我可以很容易地进入自定义转换永远不会完成并且 UI 处于奇怪状态的状态

  • UI 卡在 VC B 上,没有手势或点击工作。
  • 该应用程序没有卡住 - 我可以看到控制台日志仍在滚动并且网络活动正在运行(日志中没有错误)
  • 在这种卡住状态下暂停应用程序我可以看到 com.apple.main-thread 没有卡住。
  • 当我点击“Debug View Hierarchy”时,发生了一些奇怪的事情:在模拟屏幕上我仍然可以看到VC B 并且所有 UI 都已禁用。在视图调试器主视图上 - 我可以看到绘制的 VC A 的子视图,就好像转换完成一样。在视图调试器左树视图上-我可以看到VC B 的视图层次结构

此问题从未出现在任何先前版本的 Xcode 和/或 iOS pre 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
    })

}

打印件仅用于调试。

这是很容易重现问题的序列:

  1. 使用平移手势开始从 B 到 A 的交互式过渡,但从不完成 - 这将调用cancel()对象UIPercentDrivenInteractiveTransition+ 我可以验证动画是否完成。
  2. 点击“关闭”按钮以调用非交互式过渡来关闭 B。B 永远不会关闭,并且自定义动画永远不会完成!

在设备上,我(还)根本无法重现这个问题——所有转换都按预期工作。

4

2 回答 2

6

尝试wantsInteractiveStart = false在您的 UIPercentDrivenInteractiveTransition 中设置

于 2018-09-27T18:05:53.003 回答
5

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

为了简短起见:

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

确保关闭转换是交互式的或不是基于用户交互的,特别是在取消交互式之后,修复了问题。

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

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

于 2018-09-17T14:31:31.363 回答