How do I remove the sidebar toggle from a NavigationSplitView on iPad in landscape mode but keep it in portrait mode? Similar to how it works in the home app in iOS 17.
I have this so far but it doesn't work correctly at first launch before switching orientation once:
struct SidebarMainView: View {
@Environment(\.horizontalSizeClass) private var horizontalSizeClass
@State private var isPortrait = true
var body: some View {
NavigationSplitView {
List {
Text("1")
Text("2")
Text("3")
}
.listStyle(SidebarListStyle()).toolbar(removing: isPortrait ? .none : .sidebarToggle).navigationTitle("HP").onReceive(NotificationCenter.default.publisher(for: UIDevice.orientationDidChangeNotification)) { _ in
guard let scene = UIApplication.shared.windows.first?.windowScene else { return }
self.isPortrait = scene.interfaceOrientation.isPortrait
}
} detail: {
Text("Select a department: \(self.isPortrait ? "yes" : "no")")
}
}
}
For reference, this is what the Home app looks like in different layouts. Note the forced and optional sidebar in each layout. I want to accomplish the same.
For iOS 17+
We can use UIDevice.orientationDidChangeNotification
to detect current orientation and toolbar(removing:)
for removing sidebar toggle button.
struct ContentView: View {
@State private var deviceOrientation = UIDevice.current.orientation
var body: some View {
NavigationSplitView {
Text("sidebar")
.detectOrientation($deviceOrientation)
// After removing sidebar toggle, it was not adding when refreshing (Instead Visibility solves the problem)
// .toolbar(removing: isOrientationPortrait() ? .none : .sidebarToggle)
.toolbar(isOrientationPortrait() ? .visible : .hidden, for: .navigationBar)
} detail: {
Text("Detail")
}
}
private func isOrientationPortrait() -> Bool {
return deviceOrientation == .portrait || deviceOrientation == .portraitUpsideDown
}
}
extension View {
func detectOrientation(_ orientation: Binding<UIDeviceOrientation>) -> some View {
modifier(DetectOrientation(orientation: orientation))
}
}
struct DetectOrientation: ViewModifier {
@Binding var orientation: UIDeviceOrientation
func body(content: Content) -> some View {
content.onReceive(NotificationCenter.default.publisher(for: UIDevice.orientationDidChangeNotification)) { _ in
orientation = UIDevice.current.orientation
}
}
}
Hope It Helps !