.navigationViewStyle(StackNavigationViewStyle()) Not Working!

Hi,

My app has gotten rejected four times for this problem so bear with me....


A few weeks ago, I posted that I was having problems with my app showing a blank screen when someone went into Landscape Mode.


Someone suggested using .navigationViewStyle(StackNavigationViewStyle()) which seemed to work the first few times, and then stopped working after I sent it to have it reviewed.


I'm still having the same problem and it is becoming maddening.


Here's the code in question (again):


import SwiftUI
import Foundation

struct ContentView: View {
    var body: some View {
        
        NavigationView() {
        
            List (){
            
             Section(header: Text("Main Information"))
            {
                                         
                         
            NavigationLink(destination: Introduction())
            {
                Image(systemName: "exclamationmark.circle").resizable()
                .frame(width: 32, height: 32, alignment: .leading)
                
                Text("Introduction").tag(1)
                .font(.headline)
            
            }
            NavigationLink(destination: Definitions())
            {
                           
                Image(systemName: "questionmark.circle").resizable()
                .frame(width: 32, height: 32, alignment: .leading)
                Text("Definitions").tag(2)
                .font(.headline)
            }
                
            
            NavigationLink(destination: TypesOfAbuse())
            {
                
                Image(systemName: "table").resizable()
                .frame(width: 32, height: 32, alignment: .leading)
                Text("Types").tag(2)
                .font(.headline)
            }
                
            NavigationLink(destination: Effects())
            {
                
                Image(systemName: "exclamationmark.circle").resizable()
                .frame(width: 32, height: 32, alignment: .leading)
                Text("Effects").tag(2)
                .font(.headline)
            }
            
            NavigationLink(destination: WhereAbuseOccures())
            {
                Image(systemName: "questionmark.circle").resizable()
                .frame(width: 32, height: 32, alignment: .leading)
                Text("Where it Occurs").tag(3)
                .font(.headline)
                }
                
            NavigationLink(destination: RecognizingChildAbuse())
            {
                Image(systemName: "xmark.circle").resizable()
                .frame(width: 32, height: 32, alignment: .leading)
                Text("Recognizing Abuse").tag(4)
                .font(.headline)
                }
                
            NavigationLink(destination: ReportingSuspectedChildAbuse())
            {
               Image(systemName: "phone.arrow.right").resizable()
               .frame(width: 32, height: 32, alignment: .leading)
                Text("Reporting Child Abuse").tag(5)
                .font(.headline)
            }
                
                NavigationLink(destination: ChildrenCanBeHelped())
            {
                
                Image(systemName: "person.circle").resizable()
                .frame(width: 32, height: 32, alignment: .leading)
                Text("Children Can Be Helped").tag(7)
                       .font(.headline)
                
            }
                
            NavigationLink(destination: CountryMenu())
              {
                  Image(systemName: "phone.circle").resizable()
                  .frame(width: 32, height: 32, alignment: .leading)
                Text("Phone Numbers").tag(8)
                  .font(.headline)
              }
                  
            
                
            NavigationLink(destination: Search())
            {
                Image(systemName: "magnifyingglass.circle").resizable()
                .frame(width: 32, height: 32, alignment: .leading)
                Text("Search").tag(9)
                .font(.headline)
            }
            }
                
            Section(header: Text("App Information & Support"))
            {
                NavigationLink(destination: About())
                {
                Text("About").fontWeight(.bold)
                }
                
                NavigationLink(destination: Support())
                {
                Text("Support").fontWeight(.bold)
                }
                
            }
    
            Section(header: Text("Version"))
            {
                Text("1.0").fontWeight(.bold)
            }
                        
                
            }
            .navigationViewStyle(StackNavigationViewStyle())
            .navigationBarTitle(Text("Child Abuse"))
            .listStyle(GroupedListStyle())
            
            
        
        
        }
        
        
    }

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        Group {
            ContentView()
            .previewDevice("iPhone XS Max")
            .environment(\.colorScheme, .light)
    }
}
}
}

extension View {
    func phoneOnlyStackNavigationView() -> some View {
        if UIDevice.current.userInterfaceIdiom == .phone {
            return AnyView(self.navigationViewStyle(StackNavigationViewStyle()))
        } else {
            return AnyView(self)
        }
    }
}


As you can see on line 126, I have the suggested option.


By the way, lines 149 - 157 were from a website to try and get this working, but to no advail.


Thanks,

Dan Uff

Replies

Would be helpful to try to reproduce.


Unfortunately we miss a lot of struct definitions to compile the project.

So, I'll try to replace with phony struct Views. Hope that's not where the problem lies.

I have found a possible cause.

You applied:

.navigationViewStyle(StackNavigationViewStyle())

to List().


I applied to NavigationView().


Tested, it works (I mean, no more blank screen ). But still some navigation problems (maybe because of StackNavigationViewStyle, I will look at this). And problem when returning to Portrait.

So there are other issues…


Here is the working code (with stub structs):


import SwiftUI
import Foundation

struct ContentView: View {
    var body: some View {
        NavigationView() {
            List() {
                Section(header: Text("Main Information")) {
                    NavigationLink(destination: Introduction())  {
                        Image(systemName: "exclamationmark.circle").resizable()
                            .frame(width: 32, height: 32, alignment: .leading)
                        Text("Introduction").tag(1)
                            .font(.headline)
                    }
                    NavigationLink(destination: Definitions()) {
                        Image(systemName: "questionmark.circle").resizable()
                            .frame(width: 32, height: 32, alignment: .leading)
                        Text("Definitions").tag(2)
                            .font(.headline)
                    }
                   
                    NavigationLink(destination: TypesOfAbuse()) {
                        Image(systemName: "table").resizable()
                            .frame(width: 32, height: 32, alignment: .leading)
                        Text("Types").tag(2)
                            .font(.headline)
                    }
                   
                    NavigationLink(destination: Effects()) {
                        Image(systemName: "exclamationmark.circle").resizable()
                            .frame(width: 32, height: 32, alignment: .leading)
                        Text("Effects").tag(2)
                            .font(.headline)
                    }
                   
                    NavigationLink(destination: WhereAbuseOccures()) {
                        Image(systemName: "questionmark.circle").resizable()
                            .frame(width: 32, height: 32, alignment: .leading)
                        Text("Where it Occurs").tag(3)
                            .font(.headline)
                    }
                   
                    NavigationLink(destination: RecognizingChildAbuse()) {
                        Image(systemName: "xmark.circle").resizable()
                            .frame(width: 32, height: 32, alignment: .leading)
                        Text("Recognizing Abuse").tag(4)
                            .font(.headline)
                    }
                   
                    NavigationLink(destination: ReportingSuspectedChildAbuse()) {
                        Image(systemName: "phone.arrow.right").resizable()
                            .frame(width: 32, height: 32, alignment: .leading)
                        Text("Reporting Child Abuse").tag(5)
                            .font(.headline)
                    }
                   
                    NavigationLink(destination: ChildrenCanBeHelped()) {
                        Image(systemName: "person.circle").resizable()
                            .frame(width: 32, height: 32, alignment: .leading)
                        Text("Children Can Be Helped").tag(7)
                            .font(.headline)
                    }
                   
                    NavigationLink(destination: CountryMenu()) {
                        Image(systemName: "phone.circle").resizable()
                            .frame(width: 32, height: 32, alignment: .leading)
                        Text("Phone Numbers").tag(8)
                            .font(.headline)
                    }
                   
                    NavigationLink(destination: Search()) {
                        Image(systemName: "magnifyingglass.circle").resizable()
                            .frame(width: 32, height: 32, alignment: .leading)
                        Text("Search").tag(9)
                            .font(.headline)
                    }
                }
               
                Section(header: Text("App Information & Support")) {
                    NavigationLink(destination: About()) {
                        Text("About").fontWeight(.bold)
                    }
                   
                    NavigationLink(destination: Support()) {
                        Text("Support").fontWeight(.bold)
                    }
                }
               
                Section(header: Text("Version")) {
                    Text("1.0").fontWeight(.bold)
                }
               
            }
            .navigationBarTitle(Text("Child Abuse"))
            .listStyle(GroupedListStyle())
        }
        .navigationViewStyle(StackNavigationViewStyle())
    }
   
    struct Introduction: View {
    var body: some View {
        Text("Introduction")
        }
    }
   
    struct Definitions: View {
    var body: some View {
        Text("Definitions")
        }
    }
   
    struct TypesOfAbuse: View {
    var body: some View {
        Text("Type of abuse")
        }
    }

    struct Effects: View {
    var body: some View {
        Text("Effects")
        }
    }
   
    struct WhereAbuseOccures: View {
    var body: some View {
        Text("WhereAbuseOccures")
        }
    }
   
    struct RecognizingChildAbuse: View {
    var body: some View {
        Text("RecognizingChildAbuse")
        }
    }
   
    struct ReportingSuspectedChildAbuse: View {
    var body: some View {
        Text("ReportingSuspectedChildAbuse")
        }
    }
   
    struct ChildrenCanBeHelped: View {
    var body: some View {
        Text("ChildrenCanBeHelped")
        }
    }
   
    struct CountryMenu: View {
    var body: some View {
        Text("CountryMenu")
        }
    }
   
    struct Search: View {
    var body: some View {
        Text("Search")
        }
    }
   
    struct About: View {
    var body: some View {
        Text("About")
        }
    }
   
    struct Support: View {
    var body: some View {
        Text("Support")
        }
    }
   

    struct ContentView_Previews: PreviewProvider {
        static var previews: some View {
            Group {
                ContentView()
                    .previewDevice("iPhone XS Max")
                    .environment(\.colorScheme, .light)
            }
        }
    }
}

extension View {
    func phoneOnlyStackNavigationView() -> some View {
        if UIDevice.current.userInterfaceIdiom == .phone {
            return AnyView(self.navigationViewStyle(StackNavigationViewStyle()))
        } else {
            return AnyView(self)
        }
    }
}

I dug more and found why screen is blank: in fact the Master part is hidden. If you drag on the left part of the screen once rotated, you see the list.


So, I changed line 97

.navigationViewStyle(StackNavigationViewStyle())

into

.navigationViewStyle(DoubleColumnNavigationViewStyle())

And it is much better.


Same reason why when you click a second time on a list item, nothing occurs: that's because the page is already selected.


Conclusion: still need some fine tuning on how the Navigation is presented, but that should give a direction to search.


EDITED

1.

It should be necessary to automatically show the left pane of navigation when rotating to Landscape ; I thought that was the purpose of DoubleColumnNavigationViewStyle, but that's not enough).

I tried to implement a contional navigationViewStyle, such as

.navigationViewStyle(isLandscape ? DoubleColumnNavigationViewStyle() : DefaultNavigationViewStyle())

using this to set isLandscape:

https://stackoverflow.com/questions/57441654/swiftui-repaint-view-components-on-device-rotation

But all my attemps ended up crashing the Mac out of Applications memory.


2.

There was an issue when returning from Landscape to Portrait, hitting an item in list bcaused a double transition to the navigation.

Removing line 95 did improve largely the situation.

            .listStyle(GroupedListStyle())

Why did you add it ?

I noticed a typo that could have a serious consequence in your code (may be the cause for multiple navigation).


Preview is included in Content.


Closing curly brace line 147 should be move upward to line 137.

Still need to remove

.listStyle(GroupedListStyle())

which causes multiple navigation to the same view when you return from landcape.


Note:

You should avoid inserting too many empty lines, you loose track where you are. And use ctrl-i to re-indent code in XCode.

Should have a look here also, to see how to force display of the left navigation view when in Landscape

h ttps://medium.com/better-programming/sidebar-and-navigationview-on-macos-in-swiftui-a8b4a074a651

Thanks for all the help.


To get the app through, I had to use the "Requires Full Screen" option and disabled Landscape until I can get this problem resolved.


PLEASE feel free to keep giving me suggestions and ideas. I want to be able to use Landscape eventually.


Dan Uff

2 ideas:


- file a bug report


- on the white screen (which shows when no item selected yet), put a label telling user to drag the navigation view from the left. It is not ideal, but less confusing than present isutation

- try to exploit this links

https://stackoverflow.com/questions/57211380/collapse-a-doublecolumn-navigationview-detail-in-swiftui-like-with-collapsed-on/57215664#57215664

https://stackoverflow.com/questions/57211380/collapse-a-doublecolumn-navigationview-detail-in-swiftui-like-with-collapsed-on/57215664#57215664where Apple explain there is a bug in SwiftUI and how to use Master and Detail in this case. But that require some envirnment var and some complexity.


So, I've set this up as a start.

What I did not yet implement is when item is selected, the environment model should be changed (itemSelected = true) and the redrawing of the NavView be forced. That seem a bit hard with SwiftUI today.


Nevertheless, here is the complete code (sorry, a bit long and some comments in french).


import SwiftUI
import Foundation

class Model: ObservableObject {     // 5.1.2020
    @Published var landscape: Bool = false
    @Published var itemSelected: Bool = false


    init(isLandscape: Bool, isItemSelected: Bool) {
        self.landscape = isLandscape // Initial value
        self.itemSelected = isItemSelected // Initial value
        NotificationCenter.default.addObserver(self, selector: #selector(onViewWillTransition(notification:)), name: .myOnViewWillTransition, object: nil)
    }

    @objc func onViewWillTransition(notification: Notification) {
        guard let size = notification.userInfo?["size"] as? CGSize else { return }
        landscape = size.width > size.height
    }

}

extension Notification.Name {     // 5.1.2020
    static let myOnViewWillTransition = Notification.Name("MainUIHostingController_viewWillTransition")
}

class MyUIHostingController : UIHostingController where Content : View {     // 5.1.2020

    override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
        NotificationCenter.default.post(name: .myOnViewWillTransition, object: nil, userInfo: ["size": size])
        super.viewWillTransition(to: size, with: coordinator)
    }

}

//  With help from: https://stackoverflow.com/questions/57211380/ collapse-a-doublecolumn-navigationview-detail-in-swiftui-like-with-collapsed-on/57215664#57215664

struct ContentView: View {
    @EnvironmentObject var model: Model // 5.1.2020
  
    var body: some View {
        HStack {
            NavigationView() {
                List() {
                    Section(header: Text("Main Information")) {
                        NavigationLink(destination: Introduction())  {
                            Image(systemName: "exclamationmark.circle").resizable()
                                .frame(width: 32, height: 32, alignment: .leading)
                            Text("Introduction").tag(1)
                                .font(.headline)
                        }

                        NavigationLink(destination: Definitions()) {
                            Image(systemName: "questionmark.circle").resizable()
                                .frame(width: 32, height: 32, alignment: .leading)
                            Text("Definitions").tag(2)
                                .font(.headline)
                        }
                      
                        NavigationLink(destination: TypesOfAbuse()) {
                            Image(systemName: "table").resizable()
                                .frame(width: 32, height: 32, alignment: .leading)
                            Text("Types").tag(2)
                                .font(.headline)
                        }
                      
                        NavigationLink(destination: Effects()) {
                            Image(systemName: "exclamationmark.circle").resizable()
                                .frame(width: 32, height: 32, alignment: .leading)
                            Text("Effects").tag(2)
                                .font(.headline)
                        }
                      
                        NavigationLink(destination: WhereAbuseOccures()) {
                            Image(systemName: "questionmark.circle").resizable()
                                .frame(width: 32, height: 32, alignment: .leading)
                            Text("Where it Occurs").tag(3)
                                .font(.headline)
                        }
                      
                        NavigationLink(destination: RecognizingChildAbuse()) {
                            Image(systemName: "xmark.circle").resizable()
                                .frame(width: 32, height: 32, alignment: .leading)
                            Text("Recognizing Abuse").tag(4)
                                .font(.headline)
                        }
                      
                        NavigationLink(destination: ReportingSuspectedChildAbuse()) {
                            Image(systemName: "phone.arrow.right").resizable()
                                .frame(width: 32, height: 32, alignment: .leading)
                            Text("Reporting Child Abuse").tag(5)
                                .font(.headline)
                        }
                      
                        NavigationLink(destination: ChildrenCanBeHelped()) {
                            Image(systemName: "person.circle").resizable()
                                .frame(width: 32, height: 32, alignment: .leading)
                            Text("Children Can Be Helped").tag(7)
                                .font(.headline)
                        }
                      
                        NavigationLink(destination: CountryMenu()) {
                            Image(systemName: "phone.circle").resizable()
                                .frame(width: 32, height: 32, alignment: .leading)
                            Text("Phone Numbers").tag(8)
                                .font(.headline)
                        }
                      
                        NavigationLink(destination: Search()) {
                            Image(systemName: "magnifyingglass.circle").resizable()
                                .frame(width: 32, height: 32, alignment: .leading)
                            Text("Search").tag(9)
                                .font(.headline)
                        }
                    }
                  
                    Section(header: Text("App Information & Support")) {
                        NavigationLink(destination: About()) {
                            Text("About").fontWeight(.bold)
                        }
                      
                        NavigationLink(destination: Support()) {
                            Text("Support").fontWeight(.bold)
                        }
                    }
                  
                    Section(header: Text("Version")) {
                        Text("1.0").fontWeight(.bold)
                    }
                  
                }
                .navigationBarTitle(Text("Child Abuse"))
                //                        .listStyle(GroupedListStyle())
                //            .navigationViewStyle(StackNavigationViewStyle())
            }
            .navigationViewStyle(DoubleColumnNavigationViewStyle())
          
            Text(model.landscape && !model.itemSelected ? "Drag the Master from left": "")      


        }
        //  DoubleColumnNavigationViewStyle marche en Portrait
        // OK en Landscape, mais il faut faire apparaitre la vue Master
        // Mais quand repasse en Portrait, double navigation
      
        //  .navigationViewStyle(StackNavigationViewStyle())
        //  StackNavigationViewStyle marche mal en Portrait: on ne peut plus revenir sur un lien déja passé
        //  En landcape, multiple navigation vers la page
      
        //            .navigationViewStyle(DefaultNavigationViewStyle())
        //  DefaultNavigationViewStyle marche en Portrait
        // OK en Landscape, mais il faut faire apparaitre la vue Master
        // Mais quand repasse en Portrait, double navigation
      
        //                .navigationViewStyle(model.landscape ? DoubleColumnNavigationViewStyle() : DefaultNavigationViewStyle())
        //        .navigationViewStyle(navStyle)    // 5.1.2020 Fait déborder mémoire XCode
    }
  
    // Need to propagate the change in model.itemSelected to the ContentView.
    //  That is pretty complex
    //  https://stackoverflow.com/questions/58784475/ swiftui-view-is-not-updating-to-environmentobject-change/58878219#58878219


    struct Introduction: View {
//        @EnvironmentObject var model: Model // 5.1.2020
        var body: some View {
            Text("Introduction")
        }
    }
  
    struct Definitions: View {
        @EnvironmentObject var model: Model // 5.1.2020
        var body: some View {
            HStack {    // A try to update model… Does not work
                Button("Show/hide", action: {
                    self.model.itemSelected = true
                })
                    .offset(x: 200, y: 100)
                Text("Definitions")
            }
        }
    }

    struct TypesOfAbuse: View {
        var body: some View {
            Text("Type of abuse")
        }
    }
  
    struct Effects: View {
        var body: some View {
            Text("Effects")
        }
    }
  
    struct WhereAbuseOccures: View {
        var body: some View {
            Text("WhereAbuseOccures")
        }
    }
  
    struct RecognizingChildAbuse: View {
        var body: some View {
            Text("RecognizingChildAbuse")
        }
    }
  
    struct ReportingSuspectedChildAbuse: View {
        var body: some View {
            Text("ReportingSuspectedChildAbuse")
        }
    }
  
    struct ChildrenCanBeHelped: View {
        var body: some View {
            Text("ChildrenCanBeHelped")
        }
    }
  
    struct CountryMenu: View {
        var body: some View {
            Text("CountryMenu")
        }
    }
  
    struct Search: View {
        var body: some View {
            Text("Search")
        }
    }
  
    struct About: View {
        var body: some View {
            Text("About")
        }
    }
  
    struct Support: View {
        var body: some View {
            Text("Support")
        }
    }
}


struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        Group {
            ContentView()
                .previewDevice("iPhone XS Max")
                .environment(\.colorScheme, .light)
        }
    }
}

extension View {
    func phoneOnlyStackNavigationView() -> some View {
        if UIDevice.current.userInterfaceIdiom == .phone {
            return AnyView(self.navigationViewStyle(StackNavigationViewStyle()))
        } else {
            return AnyView(self)
        }
    }
}


And the sceneDelegate


import UIKit
import SwiftUI

class SceneDelegate: UIResponder, UIWindowSceneDelegate {

    var window: UIWindow?


    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
        // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
        // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).

        // Create the SwiftUI view that provides the window contents.
        let contentView = ContentView()

        // Use a UIHostingController as window root view controller.
        if let windowScene = scene as? UIWindowScene {
            let window = UIWindow(windowScene: windowScene)
//            window.rootViewController = UIHostingController(rootView: contentView)
            window.rootViewController = MyUIHostingController(rootView: contentView.environmentObject(Model(isLandscape: windowScene.interfaceOrientation.isLandscape, isItemSelected: false)))     // 5.1.2020
            self.window = window
            window.makeKeyAndVisible()
        }
    }

    func sceneDidDisconnect(_ scene: UIScene) {
        // Called as the scene is being released by the system.
        // This occurs shortly after the scene enters the background, or when its session is discarded.
        // Release any resources associated with this scene that can be re-created the next time the scene connects.
        // The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead).
    }

    func sceneDidBecomeActive(_ scene: UIScene) {
        // Called when the scene has moved from an inactive state to an active state.
        // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
    }

    func sceneWillResignActive(_ scene: UIScene) {
        // Called when the scene will move from an active state to an inactive state.
        // This may occur due to temporary interruptions (ex. an incoming phone call).
    }

    func sceneWillEnterForeground(_ scene: UIScene) {
        // Called as the scene transitions from the background to the foreground.
        // Use this method to undo the changes made on entering the background.
    }

    func sceneDidEnterBackground(_ scene: UIScene) {
        // Called as the scene transitions from the foreground to the background.
        // Use this method to save data, release shared resources, and store enough scene-specific state information
        // to restore the scene back to its current state.
    }

}

Apparently there are bugs in List ; some are corrected in iOS 13.3 beta4


They are not the same bug, but shwos there are problems with List. Hope yours will be corrrected as well.

https://forums.developer.apple.com/message/395130


https://stackoverflow.com/questions/59061298/cant-select-same-row-twice-in-swiftu

I encountered another annoying bug related to these kinds of issues.


After changing from Portrait to Landscape (or vice versa) List doesn't appear/behaves correctly when trying to edit it (after clicking EditButton) an the .onMove() Handler is called

You should probably close the thread now.


Waiting for a future SwiftUI release…