I'm trying to build a custom view controller transition which is interactive and interruptible with these APIs:
- UIViewControllerAnimatedTransitioning
- UIPercentDrivenInteractiveTransition
- UIViewControllerTransitioningDelegate
- UIViewPropertyAnimator
What I want to achieve is that I can present a view controller modally, and then use UIPanGestureRecognizer
to dismiss the presented view controller by dragging it downward. If I release my finger in the upper half of the screen, the transition should be cancelled, otherwise the transition will be completed successfully.
Here is the code about the problem:
func handlePanGesture(gestureRecognizer: UIPanGestureRecognizer) {
let translation = gestureRecognizer.translation(in: presentedViewController.view)
switch gestureRecognizer.state {
case .began:
interacting = true
presentingViewController.dismiss(animated: true) {
print("Dismissal Completion Callback is Called.")
// How can I know the dismissal is successful or cancelled.
}
case .changed:
let fraction = (translation.y / UIScreen.main.bounds.height)
update(fraction)
case .ended, .cancelled:
interacting = false
if (percentComplete > 0.5) {
finish()
} else {
cancel()
}
default:
break
}
}
My code works great on the aspect of UI and interaction, but I don't understand the behavior of function func dismiss(animated flag: Bool, completion: (() -> Void)? = nil)
.
In the .began
case of Pan Gesture
, presentingViewController.dismiss(animated: true) { ... }
is called, so the custom transition starts. But the completion
callback is always called no mater the dismissal transition is cancelled or not.
I watched these videos of WWDC:
They use an example code to demonstrate custom transition with UINavigationController and do not mention the dismissal callback.
presentingViewController.dismiss(animated: true) {
debugPrint("Dismissal Completion Called")
debugPrint("[ presentedViewController.transitionCoordinator?.isCancelled \(self.presentedViewController.transitionCoordinator?.isCancelled) ]")
}
In the document about the completion
parameter:
completion
The block to execute after the view controller is dismissed. This block has no return value and takes no parameters. You may specify nil for this parameter.
The Question
What is the real meaning of Completion
since it is always called after custom transition is cancelled or finished ?
When I use custom transition with presentation and dismissal, what's best practice of handling the real dismissal completion to update UI and data ?