1

Unexpectedly, SwiftUI's pushed view temporarily renders its contents with space for the hidden navigationBar upon transition. A moment later it re-renders properly. How do I prevent this behavior?

For GIF screen recording, click the image below.

jumpy render

ContentView.swift

import SwiftUI

struct ContentView: View {
    @State var goToNextView = false

    var body: some View {
        NavigationView { ZStack {
            /*@START_MENU_TOKEN@*/Color.yellow/*@END_MENU_TOKEN@*/.edgesIgnoringSafeArea(.all)
            NavigationLink(destination: SecondView(), isActive: $goToNextView) {Text("")}
                .navigationBarTitle("")
                .navigationBarHidden(true)
                .navigationBarBackButtonHidden(true)


            VStack {

                Button(action: {
                    print("Button clicked")
                    self.goToNextView = true
                }) { Text("Go to second view") }
                    .padding()
                Text("This is the first view.")

            }
        }
        .foregroundColor(Color.blue)

        }
    }
}

SecondView.swift

struct SecondView: View {

    var body: some View {

        ZStack {

            Color.purple
            .edgesIgnoringSafeArea(.all)

            .navigationBarBackButtonHidden(true)
            .navigationBarHidden(true)

            VStack { Text("Pushed view") }

        }
        .foregroundColor(Color.white)

    }
}
Beginner
  • 455
  • 7
  • 14

2 Answers2

2

I removed this behavior by utilizing a View Modifier, influenced by this answer.

Inline comments explain the changes I made.

import SwiftUI

    struct ContentView: View {
        @State var goToNextView = false

        var body: some View {
            NavigationView { ZStack {
                /*@START_MENU_TOKEN@*/Color.yellow/*@END_MENU_TOKEN@*/.edgesIgnoringSafeArea(.all)
                NavigationLink(destination: SecondView(), isActive: $goToNextView) {Text("")}
                    // Removed all nav config code here
                VStack {
                    Button(action: {
                        print("Button clicked")
                        self.goToNextView = true
                    }) { Text("Go to second view") }
                        .padding()
                    Text("This is the first view.")
                }
            }
            // Added this to hide bar
            .hiddenNavigationBarStyle()
            .foregroundColor(Color.blue)

            }
        }
    }

    struct SecondView: View {
        var body: some View {
            ZStack {
                Color.purple
                .edgesIgnoringSafeArea(.all)
                    // Added this to hide bar
                    .hiddenNavigationBarStyle()
                VStack { Text("Pushed view") }
            }
            .foregroundColor(Color.white)
        }
    }

This is the View Modifier taken from the earlier answer:

struct HiddenNavigationBar: ViewModifier {
    func body(content: Content) -> some View {
        content
        .navigationBarTitle("", displayMode: .inline)
        .navigationBarHidden(true)
    }
}

extension View {
    func hiddenNavigationBarStyle() -> some View {
        ModifiedContent(content: self, modifier: HiddenNavigationBar())
    }
}
CodeBender
  • 35,668
  • 12
  • 125
  • 132
  • This is a better answer, as you will have less code when you want to hide the Navigation Bar in multiple views. – davidev May 11 '20 at 19:07
  • 1
    Thank you. I'm putting the UI on my first app. Thanks for solving this issue and also teaching me a new handy trick for standardizing formatting across views. – Beginner May 11 '20 at 20:09
1

SwiftUI requires to set the NavigationBar Title even though you want to hide the navigation bar. In your first View you did that. In the second you didn't.

Adding this to your SecondView fixes the problem:

.navigationBarTitle("")

And SecondView in total:

struct SecondView: View {

    var body: some View {

        ZStack {

            Color.purple
            .edgesIgnoringSafeArea(.all)

            .navigationBarTitle("")
            .navigationBarBackButtonHidden(true)
            .navigationBarHidden(true)

            VStack { Text("Pushed view") }

        }
        .foregroundColor(Color.white)

    }
}
davidev
  • 7,694
  • 5
  • 21
  • 56