5

I have a TabView and I want to do animated switching between pages, like this: https://stackoverflow.com/a/54774397/5376525

animated switch between tabs

Is it possible for SwiftUI?

nomnom
  • 936
  • 10
  • 21

1 Answers1

-1

I actually just implemented this using SwiftUI. Here's what I did:

1) Create a SwiftUI view that conforms to UIViewControllerRepresentable. I used the init method to provide it an array of SwiftUI views of type AnyView. There is some work to do in the makeUIViewController and the updateUIViewController methods so we'll come back to that.

I created a typealias to pass a tuple of Views, their Image Name (assuming you're using system images) and the View name. It looks like this:

typealias TabBarItemView = (ViewName: String, ImageName: String, TargetView: AnyView)

2) You'll need to create a class that conforms to the UITabBarControllerDelegate. Within that delegate, you can override the tabBarController(_ tabBarController: UITabBarController, animationControllerForTransitionFrom fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning method.

Part of this requires you to create another class, one that conforms to UIViewControllerAnimatedTransitioning. This class requires you to implement two functions: transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval which just needs you to specify how long you want the animation to last.

The second function is animateTransition(using transitionContext: UIViewControllerContextTransitioning) which requires you to do some heavier lifting. Within this function, you'll need to design the animation that moves the views. Essentially, you should be applying a CGAffineTransform that moves the view from off screen (imagine a stage to the left or right of the screen) onto the screen while moving the other view in the same direction off-screen. At the end of the function, you can animate your transforms using something like:

UIView.animate(withDuration: animationDuration, animations: moveViewsClosure, completion: cleanUpClosure)

where animationDuration specifies how long this will take, moveViewsClosure is applying the transforms, and cleanUpClosure is actually replacing the views with one-another.

Once you have the class conforming to UIViewControllerAnimatedTransitioning you should be able to return it as the output of the UIViewControllerAnimatedTransitioning function.

3) Now that you have your delegate and animation classes created, you can assign the delegate to a UITabViewController within the SwiftUI view we started in. At the top of the struct, I created a variable of type UITabViewController and used the default initializer. Within the init function, you should set the delegate to an instance of the delegate class we created above.

4) Now we can implement the makeUIViewController and the updateUIViewController functions. Within makeUIViewController you'll need to load the array of views using the UIHostingController to enable your SwiftUI views to sit in the UIKit view controller. Once you have all your views loaded, you can return the UITabViewController from the top. Within the updateUIViewController, you will likely need to reset the delegate to the view controller. Because SwiftUI is using structs, it is not uncommon for your view to get recreated as it is updated; I have found it will lose the reference to the delegate as a result and this was how I solved it.

I realize I could have provided all of my code, but it's fairly lengthy and I think you'll have an easier time troubleshooting it if you understand the process.

binaryPilot84
  • 994
  • 6
  • 20