I am developing a library and I want to provide a default custom transition between two view controllers, the user can also provide his own implementation the first idea that comes to my my mind is to override UIViewController
and implement the UIViewControllerTransitioningDelegate
and then users can subclass my CustomTransitionViewController
is it the best way to do it ? any limitations ? is there a more elegant way using just protocols for example with default implementation ?
import UIKit
class CustomTransitionViewController: UIViewController, UIViewControllerTransitioningDelegate {
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.transitioningDelegate = self
}
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil:Bundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
self.transitioningDelegate = self
}
func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return FadeInAnimator(transitionDuration: 0.5, startingAlpha: 0.8)
}
func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return FadeInAnimator(transitionDuration: 0.5, startingAlpha: 0.8)
}
}
I think one of the most elegant (and protocol oriented) ways to do this would be with a UIViewControllerTransitioningDelegate
extension. Extend the protocol and provide a default implementation for animationController(forPresented: presenting: source:)
and animationController(forDismissed:)
. The extension would look something like this:
extension UIViewControllerTransitioningDelegate where Self: UIViewController {
func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return FadeInAnimator(transitionDuration: 0.5, startingAlpha: 0.8)
}
func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return FadeInAnimator(transitionDuration: 0.5, startingAlpha: 0.8)
}
}
And then tell your users to extend their view controllers to conform to this protocol. Since you already implemented the only requirements in a protocol extension, all they need to do is add the conformance declaration, like so:
class MyViewController: UIViewController, UIViewControllerTransitioningDelegate { }
If you want to extend all UIViewController
s to do so, you can do it with an empty extension:
extension UIViewController: UIViewControllerTransitioningDelegate { }
That should work. In my opinion, it's a very clean, elegant solution that doesn't require unnecessary subclassing. It also makes it easy to provide different implementations of animationController(forPresented: presenting: source:)
and animationController(forDismissed:)
in each view controller. Your users can just add their own implementations of the two aforementioned functions wherever they want. Also, you don't need to deal with messy Objective C stuff like associated objects.
If you're providing this functionality in some sort of prepackaged bundle and you want to hide the underlying implementation, you could declare your own protocol, make it a subprotocol of UIViewControllerTransitioningDelegate
, extend it similarly, and have your users conform to your custom protocol instead of UIViewControllerTransitioningDelegate
:
protocol MyProtocol: UIViewControllerTransitioningDelegate {
//Add your own requirements (if you have any).
}
extension MyProtocol where Self: UIViewController {
func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return FadeInAnimator(transitionDuration: 0.5, startingAlpha: 0.8)
}
func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return FadeInAnimator(transitionDuration: 0.5, startingAlpha: 0.8)
}
//Satisfy your requirements (or let your users do it).
}
class MyViewController: UIViewController, MyProtocol { }
extension UIViewController: MyProtocol { }
Whichever route you take, this solution gives you what you want without making you deal with extraneous subclassing or ugly Objective C concepts. Good luck!
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