[SwiftUI] Gray view with simple navigation

Hi guys,

I'm getting a weird navigation side effect (a half screen grey view) when moving from one view to another.

Here's the code:

    @State var text: String = ""
    
    var body: some View {
        NavigationView {
            VStack {
                TextField("TextField", text: $text)
                NavigationLink {
                    Text("Yellow view")
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
                    .background(Color.yellow)
                    Spacer()
                } label: {
                    Text("Yellow view")
                }
                Spacer()
            }
        }
        Text("Bottom View")
        .frame(maxWidth: .infinity, maxHeight: 60)
        .background(Color.red)
    }
}

And here's what I'm seeing:

Is there any way to fix it, without moving the red view inside the NavigationView hierarchy ?

The individual frames provide more information:

Try removing this spacer:

                    .background(Color.yellow)
                    Spacer()

Hi Claude,

Thanks for the answer ! Sadly it didn't resolve the issue.

The gray view only appears when the keyboard is up, so I'm suspecting it has something to do with the it,

OK, I tested. Effectively problem occurs only when you are editing the TextField and hit the YellowView button.

In fact the sequence is:

  • You type in TextField: keyboard shows in its view
  • You type the button : keyboard view still occupies screen
  • keyboards hides in the same time yellow appears. But it has only a partial screen available, because of keyboard View
  • when finished, keyboard view is freed and space becomes available for yellow view

You should try to dismiss the keyboard before firing NavigationLink.

https://stackoverflow.com/questions/57697827/swiftui-navigationlink-navigate-to-a-destination-view-after-running-account-cre

Hi Claude,

I agree, it was one of the paths I've tried to solve the issue. If there's no other solution, I think this would be good enough for my scenario.

Problem is, I don't know of an easy way to handle that, it seems I need to write some UIKit code to find out when the keyboard is up or down (I'm thinking to register for notifications for keyboarddidhide etc).

Is there a more swifty approach to it ?

Actually one simple way of doing it would be to force that the keyboard is hidden without animation. I am able to do that, on a custom textfield level like this:

                UIView.setAnimationsEnabled(false)
                textField.resignFirstResponder()
                UIView.setAnimationsEnabled(true)

But I don't know how to make it such that the bottom view is moved immediately on the bottom of the first view. If keyboard dismiss and the view would happen in an instant without animation, then moving to the next view will be a no issue.

Here is something (can probably be simplified) that works.

struct YellowView: View {
    
    var body: some View {
        Text("Yellow view")
            .frame(maxWidth: .infinity, maxHeight: .infinity)
            .background(Color.yellow)
    }
}

struct ContentView: View {
    private enum Field: Int, CaseIterable {
        case textCase
    }

    @State var isLinkActive = false // Will allow to delay
    @State var text: String = ""
   
    @FocusState private var focusedField: Field?

   var body: some View {
       NavigationView {
           VStack {
               TextField("TextField", text: $text)
                   .focused($focusedField, equals: .textCase)  // If $focusedField different, will hide keyboard

               NavigationLink(destination: YellowView(), isActive: $isLinkActive) {
                   Button(action: {
                       focusedField = nil
                       let seconds = 0.5    // Give time for keyboard to completely hide
                       DispatchQueue.main.asyncAfter(deadline: .now() + seconds) {
                           self.isLinkActive = true
                       }
                   }) {
                       Text("Go Yellow view")
                   }
               }

               Spacer()
           }
       }
       Text("Bottom View")
       .frame(maxWidth: .infinity, maxHeight: 60)
       .background(Color.red)
   }
}

With the help of:

and

If you have a single textField, you can simplify a little bit. No need for enum.

struct YellowView: View {
    
    var body: some View {
        Text("Yellow view")
            .frame(maxWidth: .infinity, maxHeight: .infinity)
            .background(Color.yellow)
    }
}

struct ContentView: View {
    let textCase = 1
    @State var isLinkActive = false // Will allow to delay
    @State var text: String = ""
   
    @FocusState private var focusedField: Int?

   var body: some View {
       NavigationView {
           VStack {
               TextField("TextField", text: $text)
                   .focused($focusedField, equals: textCase)  // If $focusedField different, will hide keyboard

               NavigationLink(destination: YellowView(), isActive: $isLinkActive) {
                   Button(action: {
                       focusedField = nil
                       let seconds = 0.4    // Give time for keyboard to hide
                       DispatchQueue.main.asyncAfter(deadline: .now() + seconds) {
                           self.isLinkActive = true
                       }
                   }) {
                       Text("Go Yellow view")
                   }
               }

               Spacer()
           }
       }
       Text("Bottom View")
       .frame(maxWidth: .infinity, maxHeight: 60)
       .background(Color.red)
   }
}

struct ContentView_Previews: PreviewProvider {
  static var previews: some View {
    ContentView()
  }
}
[SwiftUI] Gray view with simple navigation
 
 
Q