如何使用 SwiftUI 运行 iPad 上的拆分视图?

How to run the split view on iPad using SwiftUI?

似乎有一种简单的方法可以在 iPad space 上制作美观的 iOS 应用程序 运行。一个不涉及重写 SwiftUI 应用程序的方法。

基本的 SplitViewSplitViewController 问题似乎...很像一个考虑不周的问题 space...我有一个基本的 - 带有 ContentView 的显示卡- 我希望它在 iPad 上 运行...只是更大的视口...

有没有使用 SwiftUI 完成此操作的简单方法?

这就是您如何按照 Apple Fruta app 示例使用 Xcode12 设置 iPhone、iPad 和 mac 应用程序的方式,对于 [=32] =] 和 macOS11 作为最低目标。

使用这种实现 SwiftUI 的方式,您将拥有 iPad 和 mac 正在使用的拆分视图。关于iPhone,您将拥有经典的标签栏。

这是一个随时可用的代码,所以如果您不需要 mac 应用程序,只需删除 #else#end 之间的部分。我实施它是为了防止其他人发现它很方便,因为它非常适合多平台应用程序项目。 #if os(iOS)#else 之间的代码用于 iPhone 和 iPad。

查找我在代码中添加的注释,这些注释解释了创建拆分视图的时间点。

根据设备保存导航类型的 ContentView:

struct ContentView: View {

  #if os(iOS)
  @Environment(\.horizontalSizeClass) private var horizontalSizeClass
  #endif

  @ViewBuilder
  var body: some View {
    #if os(iOS)
    if horizontalSizeClass == .compact {
      TabBarNavigationView() // For iPhone
    }
    else {
      SidebarNavigationView() // For iPad
    }
    #else
    SidebarNavigationView() // For mac
      .frame(minWidth: 900, maxWidth: .infinity, minHeight: 500, maxHeight: .infinity)
    #endif
  }
}

然后,声明经典的 iPhone 选项卡栏,其中包含您的选项卡枚举 (HomeView 可以替换为您的任何 SwiftUI 视图):

enum TabItem {
  case home
}

struct TabBarNavigationView: View {

  @State private var selection: TabItem = .home

  var body: some View {
    TabView(selection: $selection) {

      NavigationView {
        HomeView() // Create a SwiftUI HomeView or add your view
      }
      .tabItem {
        Image(systemName: "house")
          .font(.headline)
          .imageScale(.medium) }
      .tag(TabItem.home)
    }
  }
}

这是将容纳 iPad 和 mac 经典拆分视图的视图。当 iPad 处于纵向模式时,您的视图将作为导航,而当将其添加到横向模式时,您的视图将被拆分。

struct SidebarNavigationView: View {

  @SceneStorage("selection")
  var selection: String?

  var content: some View {
    List(selection: $selection) {
      NavigationLink(destination: HomeView()) {
        Label(title: { Text("Home") },
              icon: { Image(systemName: "house")
                .font(.headline)
                .imageScale(.medium) })
      }
      .tag(NavigationItem.home)
    }
    .listStyle(SidebarListStyle())
  }

  var body: some View {
    NavigationView {
      #if os(iOS)
      content
      #else
      content
        .frame(minWidth: 200, idealWidth: 200, maxWidth: 200, maxHeight: .infinity)
        .toolbar {
          ToolbarItem(placement: .navigation) {
            Button(action: toggleSidebar ) {
              Image(systemName: "sidebar.left")
                .foregroundColor(.blue)
            }
          }
        }
      #endif

      // This is the part where the magic happens for the split view.
      // Instead of the Text, add any view you want in place.
      // Play here to see what fits best for you.
      Text("Content List")
        .frame(maxWidth: .infinity, maxHeight: .infinity)

      #if os(iOS)
      Text("Split view for iPad")
        .frame(maxWidth: .infinity, maxHeight: .infinity)
      #else
      Text("Split view for macOS")
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .toolbar { Spacer() }
      #endif
    }
  }
}

extension SidebarNavigationView {
  /// Show or hide the sidebar list in macOS.
  ///
  /// Needed for when the sidebar is hidden from the user   
  /// action as there is a bug in this version of SwiftUI
  /// that block the user to show the sidebar again without
  /// this hack.
  func toggleSidebar() {
    #if os(macOS)
    NSApp
      .keyWindow?
      .firstResponder?
      .tryToPerform(#selector(NSSplitViewController.toggleSidebar(_:)),
                    with: nil)
    #endif
  }
}