0

This amazing question got closed due to "lack of technical details", so I'm sure to put a plenty of here.

Setup:

  1. Create an iOS SwiftUI app
  2. Add files as follows
  3. Observe the problem

AppleApp.swift

import SwiftUI

@main
struct AppleApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

ContentView.swift

import SwiftUI

struct ContentView: View {
    @State var isLocked = true

    var body: some View {
        VStack {
            Text("Unlocked view")
                .padding()
        }.fullScreenCover(isPresented: $isLocked) {

        } content: {
            LockScreen($isLocked)
        }


    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

LockScreen.swift

import SwiftUI

struct LockScreen: View {
    @Binding var isLocked: Bool

    init(_ isLocked: Binding<Bool>) {
        self._isLocked = isLocked
    }

    var body: some View {
        ZStack {
            Color.gray
            VStack {
                Text("Locked")
                Button("Unlock") {
                    print("unlock button pressed")
                    isLocked = false
                }
            }
        }
    }
}

struct LockScreen_Previews: PreviewProvider {
    @State static var isLocked: Bool = true
    static var previews: some View {
        LockScreen($isLocked)
    }
}

The problem:

Take a look at the video: after the app launches the "unlocked view" is visible and "LockScreen" appears after a short delay with animation.

Desired outcome:

The app shows "LockScreen" just after the launch, but it's possible to dismiss it by pressing the "unlock" button.

Video of the problem

Project file with sample app

Richard Topchii
  • 7,075
  • 8
  • 48
  • 115

2 Answers2

2

Hope you find this useful. I know it doesn't have a FullScreenCover, but this will show it instantly.

import SwiftUI

struct ContentView: View {
    @State var isLocked = true
    
    var body: some View {
        if self.isLocked {
            LockScreen(isLocked: self.$isLocked)
        } else {
            VStack {
                Text("Unlocked view")
                    .padding()
            }
        }
    }
}

struct LockScreen: View {
    @Binding var isLocked: Bool
    
    var body: some View {
        ZStack {
            Color.gray
            VStack {
                Text("Locked")
                Button("Unlock") {
                    print("unlock button pressed")
                    isLocked = false
                }
            }
        }
        .ignoresSafeArea()
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
  • I've finished with a similar solution. This is as good as it could be, except there is no "slide down" animation when unlocking which I'd like to have. – Richard Topchii Nov 26 '21 at 11:59
2

Based on your comment on the @AlexanderThoren answere. I added down animation and also simplify the code.

Add a transition animation.

Add this extension to hide - show view.

extension View {
    func showLockView(isLocked: Binding<Bool>) -> some View {
        ZStack {
            self
            if isLocked.wrappedValue {
                LockScreen(isLocked: isLocked).animation(.default).transition(AnyTransition.move(edge: .bottom))
            }
        }
        .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
    }
}

And use it with your content view

struct ContentView: View {
    @State var isLocked = true
    
    var body: some View {
        VStack {
            Text("Unlocked view")
                .padding()
        }
        .showLockView(isLocked: $isLocked) // << Here
    }
}

Edit : As mentioned in the comment, here is the solution without View extension.

struct ContentView: View {
    @State var isLocked = true
    
    var body: some View {
        ZStack {
            VStack {
                Text("Unlocked view")
                    .padding()
            }
            if isLocked {
                LockScreen(isLocked: $isLocked)
                    .edgesIgnoringSafeArea(.all)
                    .animation(.default)
                    .transition(AnyTransition.move(edge: .bottom))
            }
        }
    }
}
Raja Kishan
  • 16,767
  • 2
  • 26
  • 52