18

I Have this app that uses the new sidebar introduced in iOS14 for iPad os but I can't figure out why it doesn't remember the state when its hidden

This is the sidebar struct

import SwiftUI

struct Sidebar: View {
    
    @Environment(\.managedObjectContext) var moc
    @Binding var selection : Set<NavigationItem>
    
    var body: some View {
        List(selection: $selection) {
            NavigationLink(destination: AgendaView().environment(\.managedObjectContext, moc).navigationTitle("Agenda"), label: {
                Label("Agenda", systemImage: "book")
            })
            .tag(NavigationItem.agenda)
            
            NavigationLink(destination: Text("Subjects"), label: {
                Label("Materie", systemImage: "tray.full")
            })
            .tag(NavigationItem.subjects)
            
            NavigationLink(destination: Text("Calendario"), label: {
                Label("Calendario", systemImage: "calendar")
            })
            .tag(NavigationItem.calendar)
            
            NavigationLink(destination: SettingsView().environment(\.managedObjectContext, moc).navigationTitle("Impostazioni"), label: {
                Label("Impostazioni", systemImage: "gear")
            })
            .tag(NavigationItem.settings)
            
        }
        .listStyle(SidebarListStyle())
    }
}

for tagging the elements I use a custom struct called NavigationItem

enum NavigationItem {
    case agenda
    case calendar
    case ...
}

and here is where I placed the Sidebar in the content view, as you can see if the device is an iPad (detected using sizeClasses) I use the sidebar, otherwise if its an iPhone I use the TabBar

import SwiftUI

struct ContentView: View {
    @Environment(\.horizontalSizeClass) var horizontalSizeClass
    @Environment(\.managedObjectContext) var moc
    
    @State private var selection : Set<NavigationItem> = [.agenda]
    
    @ViewBuilder
    var body: some View {
        
        if horizontalSizeClass == .compact {
            TabBar(selection: $selection)
                .environment(\.managedObjectContext, moc)
        } else {
            NavigationView {
                Sidebar(selection: $selection)
                    .environment(\.managedObjectContext, moc)
                    .navigationTitle("Menu")
            }
        }
    }
}
Luca
  • 914
  • 9
  • 18
  • 2
    Apples WWDC sample projects suffer from the bug as well. I filed a radar, you should probably, too. But a workaround for converting from sidebar to TabView would be great. – jlsiewert Jul 09 '20 at 10:38
  • 1
    Yea, i saw that the Fruta app has the same "bug", I hope this get fixed soon if apple see this has a bug – Luca Jul 09 '20 at 18:38
  • On a side note, how do you set what is selected by default? I’m using a default version of sidebar and the initial state doesn’t have anything selected. – Ryan Jul 12 '20 at 23:42
  • For the default selected item I use a custom Enum called `NavigationItem` as you can see from my code @State private var section ... and I made it coping the apple WWDC20 Fruta app that also does this thing to set the sidebar's default state, however this is not working because when i start the app there is nothing selected, hope apple fix this! – Luca Jul 13 '20 at 11:55
  • 1
    Have you found a solution? – aheze Sep 06 '21 at 23:59
  • nope, the issue is still there (I'm still on iOS14 btw) – Luca Sep 10 '21 at 16:49

2 Answers2

1

List(selection: $selection) for selection binding is macOS only. See this comment in the header:

/// On iOS and tvOS, you must explicitly put the list into edit mode for
/// the selection to apply.

As a workaround you could make the previously selected row appear bold, e.g.

 NavigationLink(
        destination: HomeView(),
        tag: Screen.home,
        selection: $selection,
        label: {
            Label("Home", systemImage: "house" )
        })
        .font(Font.headline.weight(selection == Screen.home ? .bold : .regular))

For more see this answer.

malhal
  • 26,330
  • 7
  • 115
  • 133
0

If you don't need to be able to select multiple rows in your sidebar, change your selection definition to:

@Binding var selection: NavigationItem?

Caveat: If you're interested in using the same selection variable for a TabView, that won't work. You'll need to define another property as NavigationItem that's not an optional.