0

With the following code, Useless View is shown on app startup for iPads in portrait mode. One press of the Back button results in the detail view showing "Link 1 destination". Only upon the second press is the sidebar shown. This is not the behavior we'd want for pretty much any app.

If we remove the Useless View from the code, we get a blank screen upon startup and we still have to press the back button once to get to the Link 1 destination, and twice to get to the sidebar. Also, the styling of the list in the sidebar appears less desirable.

The behavior we want is Link 1 destination shown on app startup and a single press of the Back button bringing us to the sidebar. Is this completely standard behavior that we'd expect for any app even possible with SwiftUI 3?

struct ContentView: View {
    @State var selection: Int? = 0
    var body: some View {
        NavigationView {
            List {
                NavigationLink("Link 1", tag: 0, selection: $selection) {
                    Text("Link 1 destination")
                }
                NavigationLink("Link 2", tag: 1, selection: $selection) {
                    Text("Link 2 destination")
                }
            }
            
            //If we delete the Useless View, we still have to press Back twice
            //to get to the sidebar nav.
            Text("Useless View")
                .padding()
        }
    }
}
Steve M
  • 9,296
  • 11
  • 49
  • 98
  • Yes, it is *by design*. If you don't need it then use stack navigation view style, like in https://stackoverflow.com/a/62624598/12299030 – Asperi Oct 26 '21 at 04:18
  • @Asperi I’m going for double column. The problem is it’s not working correctly. The “Useless view” should be removed because one of the navigation links is selected. Look at how Apple Music or many other apps work in portrait on iPad. If the app was stopped and you enter it, you press the navigation back button once to see the sidebar with the current pane selected. You can’t do this with SwiftUI. – Steve M Oct 26 '21 at 13:02
  • 1
    [This blog post](https://lostmoa.com/blog/SummoningSplitViewSidebar/) may help. – Yrb Oct 26 '21 at 13:13
  • @Yrb Wow! thank you for taking the time to respond, it solves the issue! If you post it as an answer I'll accept. – Steve M Oct 26 '21 at 13:55
  • @Asperi The point is SwiftUI fails to support very simple cases out of the box, and you have to do arcane tinkering in the UIKit underpinnings, as was shown in this case, to get things working correctly. I've found this very common with SwiftUI. – Steve M Oct 26 '21 at 14:08

1 Answers1

0

@Yrb comment pointed to the right track with tinkering with underlying UIKit UISplitViewController to be forced to show the primary column. However, with somewhat heavy views in the Detail, there is some flashing of the primary column appearing and disappearing on slower iPads. So I did this with the Introspect library:

struct ContentView: View {
    @State var selection: Int? = 0
   
    var body: some View {
        NavigationView {
            List {
                NavigationLink("Link 1", tag: 0, selection: $selection) {
                    Text("Link 1 destination")
                }
                NavigationLink("Link 2", tag: 1, selection: $selection) {
                    Text("Link 2 destination")
                }
            }
            //In my case I never have a 'Nothing Selected' view, you could replace EmptyView() here
            //with a real view if needed.
            EmptyView()
        }
        .introspectSplitViewController { svc in
            if isPortrait { //If it's done in landscape, the primary will be incorrectly disappeared
                svc.show(.primary)
                svc.hide(.primary)
            }
        }
    }
}

This presents as we'd expect, with no flashing or other artifacts.

Steve M
  • 9,296
  • 11
  • 49
  • 98