In SwiftUI we use NavigationView
and NavigationLink
views to perform navigations (what we used to call segue
in UIKit
). The standard segue in UIKit is the show
segue. In SwiftUI we can simply do:
struct ContentView: View {
var body: some View {
NavigationView {
VStack {
NavigationLink(destination: Text("Destination")) {
Text("Navigate!")
}
}
}
}
}
to have the exact same effect (even if the word segue
has disappeared).
Sometimes (actually rather often) we need to customise the segue animation.
Animates
(true/false) in the
attribute inspector by clicking on a segue. This way the destination view controller appears immediately in place of the source view controller.UIViewControllerAnimatedTransitioning
protocol. All the magic happens in the animateTransition
method that gives us access to the source view controller and the destination view controller.For example, a simple cross-fade segue animation could be something like:
-(void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext{
UIView* containerView = [transitionContext containerView];
UIViewController* fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
UIViewController* toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
toVC.view.alpha = 0;
[containerView addSubview:toVC.view];
[UIView animateWithDuration:1 animations:^{
toVC.view.alpha = 1;
fromVC.view.alpha = 0;
} completion:^(BOOL finished) {
[fromVC.view removeFromSuperview];
[transitionContext completeTransition:YES];
}];
}
Now the question: how can I get the same in SwiftUI? Is it possible not to animate a navigation or to customise the navigation animation? I expected to be able to do:
struct ContentView: View {
var body: some View {
NavigationView {
VStack {
NavigationLink(destination: Text("Destination")) {
Text("Navigate!")
}
}
}
.animation(nil)
}
}
or something similar to prevent the animation (or to add a custom animation), but nothing changes.
SwiftUI has built-in support for animations with its animation() modifier. To use this modifier, place it after any other modifiers for your views, tell it what kind of animation you want, and also make sure you attach it to a particular value so the animation triggers only when that specific value changes.
withAnimation() takes a parameter specifying the kind of animation you want, so you could create a three-second linear animation like this: withAnimation(.linear(duration: 3)) Explicit animations are often helpful because they cause every affected view to animate, not just those that have implicit animations attached.
Before NavigationStack and NavigationSplitView , SwiftUI introduced the NavigationView and NavigationLink structs. These two pieces work together to allow navigation between views in your application. The NavigationView is used to wrap the content of your views, setting them up for subsequent navigation.
If you want a SwiftUI view to start animating as soon as it appears, you should use the onAppear() modifier to attach an animation.
Unfortunately it's still not possible to customise the NavigationView
transition animations in SwiftUI (xCode 11.3.1).
Looking for a way to do that I ended up creating this open source project called swiftui-navigation-stack
(https://github.com/biobeats/swiftui-navigation-stack) that contains the NavigationStackView
, a view that mimics the navigation behaviours of the standard NavigationView
adding some useful features. For example you can turn off the transition animations or you can customise them with the transition you prefer.
Months ago I asked here above how to turn off transition animations. To do that you can use the NavigationStackView
this way:
struct ContentView : View {
var body: some View {
NavigationStackView(transitionType: .none) {
ZStack {
Color.yellow.edgesIgnoringSafeArea(.all)
PushView(destination: View2()) {
Text("PUSH")
}
}
}
}
}
struct View2: View {
var body: some View {
ZStack {
Color.green.edgesIgnoringSafeArea(.all)
PopView {
Text("POP")
}
}
}
}
If you specify .none
as transitionType
you can turn off the animations. PushView
and PopView
are two views that allow you push and pop views (similar to the SwiftUI NavigationLink
).
The result is:
If you, instead, want to customise the transition animation (as I asked in the question here above with the cross-fade example) you can do like this:
struct ContentView : View {
let navigationTransition = AnyTransition.opacity.animation(.easeOut(duration: 2))
var body: some View {
NavigationStackView(transitionType: .custom(navigationTransition)) {
ZStack {
Color.yellow.edgesIgnoringSafeArea(.all)
PushView(destination: View2()) {
Text("PUSH")
}
}
}
}
}
struct View2: View {
var body: some View {
ZStack {
Color.green.edgesIgnoringSafeArea(.all)
PopView {
Text("POP")
}
}
}
}
For a cross-fase transition I specified:
let navigationTransition = AnyTransition.opacity.animation(.easeOut(duration: 2))
a cross fade transition that lasts 2 seconds. Then I passed this transition to the NavigationStackView
:
NavigationStackView(transitionType: .custom(navigationTransition))
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