交互式关闭模态视图控制器时出现故障

JGu*_*Guo 7 interactive modalviewcontroller ios swift

我正在使用UIViewControllerAnimatedTransitioningUIPercentDrivenInteractiveTransition以交互方式关闭一个模态呈现的视图控制器.没什么太花哨的.但我注意到,当交互开始时偶尔会出现一个小问题.如果使用.curveEaseOut选项进行动画制作会变得更加明显.我正在关注的一些在线教程(https://www.thorntech.com/2016/02/ios-tutorial-close-modal-dragging/)也会发生同样的事情.当我第一次将它向下拖动时,你可以看到gif中的故障.有什么建议?

在此输入图像描述

MyDismissAnimator

class SlideInDismissAnimator: NSObject, UIViewControllerAnimatedTransitioning {

    // ...

    func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {

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

        let presentedFrame = transitionContext.finalFrame(for: presentedVC)
        var dismissedFrame = presentedFrame
        dismissedFrame.origin.y = transitionContext.containerView.frame.size.height

        transitionContext.containerView.insertSubview(toVC.view, belowSubview: presentedVC.view)
        }
        let duration = transitionDuration(using: transitionContext)

        UIView.animate(withDuration: duration, delay: 0, options: .curveEaseOut, animations: {
            presentedVC.view.frame = dismissedFrame
        }) { _ in
            if transitionContext.transitionWasCancelled {
                toVC.view.removeFromSuperview()
            }
            transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

MyInteractor

class SwipeInteractionController: UIPercentDrivenInteractiveTransition {

    var interactionInProgress = false
    private var shouldCompleteTransition = false
    private weak var viewController: UIViewController!

    init(viewController: UIViewController) {
        self.viewController = viewController
        super.init()
        let gesture = UIPanGestureRecognizer(target: self, action: #selector(handleGesture(_:)))
        viewController.view?.addGestureRecognizer(gesture)
    }

    @objc func handleGesture(_ gestureRecognizer: UIPanGestureRecognizer) {
        let translation = gestureRecognizer.translation(in: gestureRecognizer.view!.superview!)
        var progress = (translation.y / viewController.view.bounds.height)
        progress = CGFloat(fminf(fmaxf(Float(progress), 0.0), 1.0))

        switch gestureRecognizer.state {
        case .began:
            interactionInProgress = true
            viewController.dismiss(animated: true, completion: nil)

        case .changed:
            shouldCompleteTransition = progress > 0.3
            update(progress)

        case .cancelled:
            interactionInProgress = false
            cancel()

        case .ended:
            interactionInProgress = false
            if shouldCompleteTransition {
                finish()
            } else {
                cancel()
            }
        default:
            break
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

fla*_*rld 8

我很确定这是UIPercentDrivenInteractiveTransition的一个错误,但我能够解决这个问题:

调用dismiss()后,如果未尽快更新进度,则会发生错误.发生这种情况是因为平移手势识别器的.changed状态仅在您拖动时触发.所以如果你慢慢拖动,在调用时间.begin和调用第一个.changed之间,dismiss过渡将开始动画.

您可以在模拟器中通过非常缓慢地逐个像素地拖动视图来查看此内容,直到调用.begin.只要.changed不再被调用,转换将实际完成,您将看到视图一直向下动画并且转换完成.

但是,简单地在.dismiss()之后调用update(progress)也不起作用,我相信因为dismiss动画还没有开始.(直到下一个runloop或其他东西)

我的"黑客"解决方案是在非常短的时间内发送异步,有效地设置进度并在动画开始之前暂停动画.

case .began:
    interactionInProgress = true
    viewController.dismiss(animated: true, completion: nil)
    DispatchQueue.main.asyncAfter(deadline: .now() + 0.001) {
        self.update(progress)
    }
Run Code Online (Sandbox Code Playgroud)


Ser*_*rov 1

如果您使用自定义解雇过渡动画师,则不应将 toViewController 的视图作为子视图添加到 transitionContext 的容器视图中。它已经处于层次结构中。该错误发生在我的同一案例中,但我同时使用了解雇和出现自定义动画。我认为只有自定义解雇动画也会发生这种情况。
删除这一行:

transitionContext.containerView.insertSubview(toVC.view, belowSubview: presentedVC.view)
Run Code Online (Sandbox Code Playgroud)

在这种情况下,您应该做的就是将动画块中 fromViewController 的框架更改为您想要的。