Animation in SwiftUI not working properly

1.3k views Asked by At

Does someone know why the following is not animation and is not working entirely and how to fix that? The problem is that some of our animation is not shown in this case. Maybe there is a workaround or so? I read articles and so on for hours and hours now... found nothing

What I'm trying to achieve in the end is:

  1. The SignUpLogin screen has both .move(edge: .top) and .opacity animations when appearing and disappearing

  2. Logout screen has both: .blur and .opacity animation when appearing and disappearing.

Blur and Opacity stop working when the views are reappearing (but they work when disappearing, see gif).

Xcode 12, iOS 14 enter image description here

import SwiftUI
import Foundation
import Combine

class ViewRouter: ObservableObject {
    @Published var signUpLoginView_active: Bool = true
    @Published var newUserView_active: Bool = false
}
struct ContentView: View {
    @EnvironmentObject var viewRouter: ViewRouter
    @Environment(\.colorScheme) var colorScheme
    var body: some View {
        ZStack {
            if colorScheme == .dark {
                Color.white.ignoresSafeArea()
            } else {
                Color.black.ignoresSafeArea()
            }
            if viewRouter.newUserView_active {
                NewUserView()
                    .transition(.opacity)
                    .zIndex(4)
            }
            if viewRouter.signUpLoginView_active {
                SignUpLoginView()
                    .transition(.move(edge: .top))
                    .zIndex(5)
            }
        }
        .edgesIgnoringSafeArea(.all)
    }
}
struct SignUpLoginView: View {
    @EnvironmentObject var viewRouter: ViewRouter
    @Environment(\.colorScheme) var colorScheme
    var body: some View {
        ZStack() {
            colorScheme == .dark ? Color.black.ignoresSafeArea().zIndex(3) : Color.white.ignoresSafeArea().zIndex(3)
            if colorScheme == .dark {
                Color.white.ignoresSafeArea()
                    .opacity(viewRouter.signUpLoginView_active ? 0 : 1)
                    .zIndex(4)
            } else {
                Color.black.ignoresSafeArea()
                    .opacity(viewRouter.signUpLoginView_active ? 0 : 1)
                    .zIndex(4)
            }
//
            Button("Login") {
                withAnimation(.easeInOut(duration: 3)) {
                    viewRouter.signUpLoginView_active.toggle()
                    viewRouter.newUserView_active.toggle()
                }
            }.zIndex(3)
        }
    }
}
struct NewUserView: View {
    @EnvironmentObject var viewRouter: ViewRouter
    @Environment(\.colorScheme) var colorScheme
    var body: some View {
        ZStack {
            TabView {
                Button("Logout") {
                    withAnimation(.easeInOut(duration: 3)) {
                        viewRouter.signUpLoginView_active.toggle()
                        viewRouter.newUserView_active.toggle()
                    }
                }
                  .tabItem {
                     Image(systemName: "person.crop.circle.fill")
                     Text("My Profile")
                  }
            }
        }
        .blur(radius: (viewRouter.signUpLoginView_active ? 3 : 0), opaque: true)
        .padding(viewRouter.signUpLoginView_active ? -20 : 0)
    }
}
1

There are 1 answers

1
Asperi On

Still not clear what is what (because you talk about Login, but in code First/Second), but the following might be helpful for how operate with transitions between views. (of course you can use any other transitions or combinations of them).

Tested with Xcode 12 / iOS 14

struct First: View {
    @EnvironmentObject var viewRouter: ViewRouter
    var body: some View {
        ZStack {
            Color.red
            Button("First View") {
               viewRouter.signUpLoginView_active.toggle()
            }
        }
    }
}

struct Second: View {
    @EnvironmentObject var viewRouter: ViewRouter
    var body: some View {
        ZStack {
            Color.orange
            Button("Second View") {
               viewRouter.signUpLoginView_active.toggle()
            }
        }

    }
}

struct ContentView: View {
    @EnvironmentObject var viewRouter: ViewRouter
    var body: some View {
        ZStack {
        if viewRouter.signUpLoginView_active {
            First()
               .transition(.move(edge: .top))   // transition here
        }
        if !viewRouter.signUpLoginView_active {
            Second()
                .blur(radius: viewRouter.signUpLoginView_active ? 3 : 0)
                .transition(.move(edge: .top)) // and here
        }
        }
        .animation(.easeInOut(duration: 3)) // animation on container
        .edgesIgnoringSafeArea(.all)
    }
}