#if os(iOS) import SwiftUI import UIKit /// Blendet die vom System gezeichnete Seitenleiste und Tableiste aus. /// /// Der Grund ist das Aussehen, nicht das Verhalten. `UITabBarController` /// zeichnet seine Seitenleiste auf dem iPad als schwebende Fläche und auf dem /// Mac angeklebt am Fensterrand — und das lässt sich nicht umstellen. /// `preferredLayout = .overlap` ist die dafür vorgesehene Bitte; macOS verwirft /// sie stillschweigend. Gemessen, nicht vermutet. /// /// Statt deshalb die ganze Navigation selbst zu bauen, bleibt der /// `TabView` **stehen** und verliert nur sein Kleid: Auswahl, getrennte /// Navigationsstapel je Eintrag, erhaltener Scrollstand beim Wechseln, /// Zustandspflege — all das macht weiter das System. Gezeichnet wird darüber. /// /// Dass das geht, war kein Ratschluss: derselbe Griff hat die Leiste /// versuchsweise schon einmal verschwinden lassen. struct TabChromeSuppressor: UIViewControllerRepresentable { func makeUIViewController(context: Context) -> UIViewController { Probe() } func updateUIViewController(_ controller: UIViewController, context: Context) {} /// Ein Controller, der nichts zeigt und nur da ist, um im Baum zu stehen. private final class Probe: UIViewController { override func didMove(toParent parent: UIViewController?) { super.didMove(toParent: parent) suppress() } override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) // Ein zweites Mal: beim ersten Anhängen steht der Tab-Controller // noch nicht zwingend im Baum. suppress() } override func viewWillLayoutSubviews() { super.viewWillLayoutSubviews() // Und bei jedem Umbau: das System stellt die Leisten wieder her, // wenn sich die Größenklasse ändert — beim Drehen etwa. suppress() } private func suppress() { guard let controller = Self.tabBarController(from: self) else { return } // Erst die Form festlegen, dann ausblenden — und zwar auf die // Tableiste, nicht auf die Seitenleiste. // // Nur `sidebar.isHidden = true` reichte nicht: auf dem Mac stand // die System-Seitenleiste danach wieder da, mit eigenem Pfeil und // eigenem Knopf, hinter unserer. Solange `mode` auf `tabSidebar` // steht, gehört die Seitenleiste zur Darstellung und das System // stellt sie wieder her. Steht `mode` auf `tabBar`, gibt es keine // Seitenleiste mehr, die zurückkommen könnte — und die Tableiste // ist ausgeblendet. if controller.mode != .tabBar { controller.mode = .tabBar } if !controller.isTabBarHidden { controller.isTabBarHidden = true } if !controller.sidebar.isHidden { controller.sidebar.isHidden = true } } /// Sucht vom eigenen Platz aus nach oben bis zur Wurzel und von dort /// nach unten: die Leiste liegt in der SwiftUI-Sicht *über* uns, die /// reine Elternkette führt an ihr vorbei. private static func tabBarController(from start: UIViewController) -> UITabBarController? { var root = start while let parent = root.parent { root = parent } return search(root) } private static func search(_ controller: UIViewController) -> UITabBarController? { if let found = controller as? UITabBarController { return found } for child in controller.children { if let found = search(child) { return found } } return nil } } } #endif