如何在 SwiftUI 中显示 iPad 和纵向模式下的侧边栏

Iva*_*ang 5 swiftui ipados swiftui-navigationview swiftui-navigationsplitview

我在 iPad 上有一个主细节应用程序,当以纵向模式运行该应用程序时,侧边栏被隐藏。我需要按“后退”按钮才能打开侧边栏。

谁能帮我默认显示侧边栏?我找到了一个答案,建议在应用程序处于纵向时使用 StackNavigationViewStyle,但随后该应用程序看起来就像一个巨大的 iPhone,并且像侧边栏一样消失了主类以显示为视图。

这就是我的代码。

struct ContentView: View {
    var body: some View {
        NavigationView {
            MyMasterView()
            DetailsView()
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

struct MyMasterView: View {

    var people = ["Option 1", "Option 2", "Option 3"]

    var body: some View {

        List {
            ForEach(people, id: \.self) { person in
                NavigationLink(destination: DetailsView()) {
                    Text(person)
                }
            }
        }

    }
}

struct DetailsView: View {

    var body: some View {
        Text("Hello world")
            .font(.largeTitle)
    }
}
Run Code Online (Sandbox Code Playgroud)

谢谢

小智 5

可以做到,但目前需要通过 UIViewRepresentable 访问 UIKit 的 UISplitViewController。这是一个基于此处描述的解决方案的示例。

import SwiftUI
import UIKit

struct UIKitShowSidebar: UIViewRepresentable {
  let showSidebar: Bool
  
  func makeUIView(context: Context) -> some UIView {
    let uiView = UIView()
    if self.showSidebar {
      DispatchQueue.main.async { [weak uiView] in
        uiView?.next(of: UISplitViewController.self)?
          .show(.primary)
      }
    } else {
      DispatchQueue.main.async { [weak uiView] in
        uiView?.next(of: UISplitViewController.self)?
          .show(.secondary)
      }
    }
    return uiView
  }
  
  func updateUIView(_ uiView: UIViewType, context: Context) {
    DispatchQueue.main.async { [weak uiView] in
      uiView?.next(
        of: UISplitViewController.self)?
        .show(showSidebar ? .primary : .secondary)
    }
  }
}

extension UIResponder {
  func next<T>(of type: T.Type) -> T? {
    guard let nextValue = self.next else {
      return nil
    }
    guard let result = nextValue as? T else {
      return nextValue.next(of: type.self)
    }
    return result
  }
}


struct ContentView: View {
  var body: some View {
    NavigationView {
      List {
        NavigationLink("Primary view (a.k.a. Sidebar)", destination: DetailView())
      }
      NothingView()
    }
  }
}

struct DetailView: View {
  var body: some View {
    Text("Secondary view (a.k.a Detail)")
  }
}

struct NothingView: View {
  @State var showSidebar: Bool = false
  var body: some View {
    Text("Nothing to see")
    if UIDevice.current.userInterfaceIdiom == .pad {
      UIKitShowSidebar(showSidebar: showSidebar)
        .frame(width: 0,height: 0)
        .onAppear {
            showSidebar = true
        }
        .onDisappear {
            showSidebar = false
        }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)