I am using UIViewControllerAnimatedTransitioning
and UIPercentDrivenInteractiveTransition
to interactively dismiss a modally presented view controller. Nothing too fancy. But I noticed there is occasionally a small glitch just when the interaction starts. It becomes more noticeable if it is animated with .curveEaseOut
option. Same thing happens with some online tutorial I am following (https://www.thorntech.com/2016/02/ios-tutorial-close-modal-dragging/). You can see the glitch in the gif when I drag it down for the first time. Any suggestions?
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)
}
}
}
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
}
}
}
I'm pretty sure this is a bug with the UIPercentDrivenInteractiveTransition, but I was able to resolve this:
The bug occurs when the progress is not updated as soon as possible after dismiss() is called. This happens because the pan gesture recognizer's .changed state is only triggered as you're dragging. So if you're dragging slowly, between the time .begin is called and the first .changed is called, the dismiss transition will start to animate.
You can see this in the simulator by very slowly dragging on the view, pixel by pixel, until .begin is called. As long as .changed doesn't get called again, the transition will actually complete itself and you'll see the view animate all the way down and transition complete.
However, simply calling update(progress) after .dismiss() doesn't work either, I believe because the dismiss animation hasn't begun yet. (until the next runloop or something)
My "hack" solution was to dispatch async with a very tiny amount of time, effectively setting the progress and halting the animation before it begins.
case .began:
interactionInProgress = true
viewController.dismiss(animated: true, completion: nil)
DispatchQueue.main.asyncAfter(deadline: .now() + 0.001) {
self.update(progress)
}
For interative dissmiss, the animation delay must be greater than 0 on iOS 11.
ref: https://github.com/jonkykong/SideMenu/blob/master/Pod/Classes/SideMenuTransition.swift#L510
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With