NEW: My new book Pro SwiftUI is out now – level up your SwiftUI skills today! >>

SOLVED: Login screen animation

Forums > SwiftUI

I'm dealing with my login screen. For that, I've defined an @AppStorage property. On change of scenePhase, I toggle it to false, and call FaceIDAuthentication method when it comes to active:

@main
struct MyApp: App {
@AppStorage("appBlocked") private var appBlocked = false
@Environment(\.scenePhase) var phase
...
MainView()
   .onChange(of: phase) { (newPhase) in
                    switch newPhase {
                    case .active : print("App is active")
                        //**
                        if appBlocked {
                                faceIdAuthentication()
                        }
                    case .inactive : print("App is inactive")
                    case .background : print("App is on background")
                            appBlocked = true
                    default: print("default")
                    }
                }

On my MainView (second on the hiearchy), I condition all shown content to this value:

struct MainView: View {

@AppStorage("appBlocked") private var appBlocked = false

var body: some View {

        if appBlocked {
            LoginView()
                .transition(.opacity)
        } else {

        //App regular views...

I change this value on Login view (password, just in case FaceId fails, or is not on) with:

if inputPassword == password {
       withAnimation {
             appBlocked = false
        }
     } else {
incorrectPassword = true
     }

And on FaceIdAthentication with:

if sucess {
     withAnimation {
           appBlocked = false
      }

Both login methods (password and FaceId) work like a charm. But animations don't: no animation (opacity of MainView, or the other two on changing the value) at all is used when "unpresenting" LoginView.

Is this the correct way of doing so? Explained here: https://www.hackingwithswift.com/quick-start/swiftui/how-to-add-and-remove-views-with-a-transition

Is it correct monitoring @AppStore (UserDefaults) for animations to fire? Have I to add any aditional modifier to my LoginView() on MainView call, maybe?

   

@Bnerd  

An idea..I don't know if it would work.. but what if you change

if appBlocked {
            LoginView()
                .transition(.opacity)
        }

to

.animation(.easeInOut, value: appBlocked )

The animation will be triggerred once the the appBlocked value will change..

   

Thanks, @Bnerd. Efectively: passing the value to be directly monitored... But still not working.

Could it be related to the fact that I use this way as well on @main view? must animation be there? (marked whith ** above)? But this case is only related to FaceID call. It must work with password, not being used then.

   

@Bnerd  

As per my understanding the .animation goes to what you want to animate. Login -> Main .animaiton goes to Main Main -> Login .animaiton goes to Login

Give it a try

   

I've moved the method from MainView...

var body: some View {
  if appBlocked {
     LoginView()
        .animation(.easeInOut, value: appBlocked)
} else {
    //General view...

...to @main App struct:

WindowGroup {
   if appBlocked {
       LoginView()
           .animation(.easeInOut, value: appBlocked)
    } else {
       MainView()

Thus, one level higher, to the top of app hiearchy. Thinking with your idea that, as appBlocked toggle is received before on "top" @main app structure, I cannot see it on "lower" MainView().

But still no animation. Any further ideas?

   

Finally, after much google research, I've found a workaround to make it work.

I've moved LoginView showing logic from @main app struct to the second hierarchical view, MainView. I've placed there the two views –regular behind, and login at front– on a ZStack, adding conditional for LoginView to be shown, and a modifier .zIndex(1) to keep its position on the stack when hiding/showing it. Finally, .animation modifier attached to ZStack itself:

struct MainView: View {

  @AppStorage("appBlocked") private var appBlocked = false

  var body: some View {
      ZStack {
           //My regular view

           if appBlocked {
                LoginView()
                   .zIndex(1)
            }
       }        
       .animation(.easeInOut(duration: 0.5), value: appBlocked)
  }
}

This way, animation works perfectly.

   

Hacking with Swift is sponsored by Play

SPONSORED Play is the first native iOS design tool created for designers and engineers. You can install Play for iOS and iPad today and sign up to check out the Beta of our macOS app with SwiftUI code export. We're also hiring engineers!

Click to learn more about Play!

Sponsor Hacking with Swift and reach the world's largest Swift community!

Reply to this topic…

You need to create an account or log in to reply.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.