像在UISplitViewController上折叠一样,在SwiftUI中折叠doubleColumn NavigationView详细信息?

MSc*_*ler 12 uisplitviewcontroller ios swiftui

因此,当我在SwiftUI中列出列表时,会获得“免费”的主从详细信息拆分视图。

因此,例如:

import SwiftUI

struct ContentView : View {
    var people = ["Angela", "Juan", "Yeji"]

    var body: some View {
        NavigationView {
            List {
                ForEach(people, id: \.self) { person in
                    NavigationLink(destination: Text("Hello!")) {
                        Text(person)
                    }
                }
            }
            Text("")
        }
    }
}

#if DEBUG
struct ContentView_Previews : PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
#endif
Run Code Online (Sandbox Code Playgroud)

如果iPad模拟器在横向,并且第一个详细信息屏幕是表情符号,我会得到splitView。但是,如果人们点击名称,则详细信息视图为“ Hello!”。

一切都很棒。

但是,如果我以纵向方式运行iPad,则表情符号会向用户表示欢迎,然后就不会显示列表。您必须从左向右滑动才能使列表从侧面显示。

有谁知道一种显示导航栏的方法,该导航栏可以让用户点击以查看左侧的项目列表?因此,它不是仅带有表情符号的屏幕吗?

我不愿意留下一个注释,上面写着“从左侧扫入以查看文件/人员/所有内容的列表”

我记得UISplitViewController有一个可以设置的折叠属性。这里有这样的东西吗?

Ket*_*dra 8

在Xcode 11 beta 3中,Apple已添加.navigationViewStyle(style:)到NavigationView。

在此处输入图片说明

已针对Xcode 11 Beta 5更新。
创建MasterView()和DetailsView()。

struct MyMasterView: View {

    var people = ["Angela", "Juan", "Yeji"]

    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)

在我的ContentView中:

var body: some View {

        NavigationView {

            MyMasterView()

            DetailsView()

        }.navigationViewStyle(DoubleColumnNavigationViewStyle())
         .padding()
    }
Run Code Online (Sandbox Code Playgroud)

输出:

在此处输入图片说明

  • 填充,是吗?那太随意了。我会尽快尝试! (4认同)
  • 我尝试了一下,看起来,一旦添加了填充,就无法关闭侧边栏(这是必要的行为),以使Master View进入全屏状态。因此,它仍然不像我希望的那样。您可以使用变量将padding设置为0,以禁用边栏,但是似乎没有什么好办法通过NavigationLink等触发它。无论如何,这都是有点棘手,所以我可能需要通过反馈进行报告并等待下一个Beta。 (4认同)
  • 这不是解决方案,因为(如预期的那样)它在外部增加了填充。这意味着视图无法使用整个屏幕。 (4认同)

Sta*_* K. 6

目前,在 Xcode 11.2.1 中它仍然没有任何改变。我在 iPad 上使用 SplitView 时遇到了同样的问题,并通过在 Ketan Odedra 响应中添加填充来解决它,但对其进行了一些修改:

var body: some View {
    GeometryReader { geometry in
        NavigationView {
            MasterView()
            DetailsView()
        }
        .navigationViewStyle(DoubleColumnNavigationViewStyle())
        .padding(.leading, leadingPadding(geometry))
    }
}

private func leadingPadding(_ geometry: GeometryProxy) -> CGFloat {
    if UIDevice.current.userInterfaceIdiom == .pad {
        return 0.5
    }
    return 0
}
Run Code Online (Sandbox Code Playgroud)

这在模拟器中完美运行。但是当我提交我的应用程序进行审核时,它被拒绝了。这个小技巧在审阅者设备上不起作用。我没有真正的 iPad,所以我不知道是什么原因造成的。试试吧,也许它对你有用。

虽然它对我不起作用,但我请求 Apple DTS 的帮助。他们回复我说,目前 SwiftUI API 不能完全模拟 UIKit 的 SplitViewController 行为。但是有一个解决方法。您可以在 SwiftUI 中创建自定义 SplitView:

struct SplitView<Master: View, Detail: View>: View {
    var master: Master
    var detail: Detail

    init(@ViewBuilder master: () -> Master, @ViewBuilder detail: () -> Detail) {
        self.master = master()
        self.detail = detail()
    }

    var body: some View {
        let viewControllers = [UIHostingController(rootView: master), UIHostingController(rootView: detail)]
        return SplitViewController(viewControllers: viewControllers)
    }
}

struct SplitViewController: UIViewControllerRepresentable {
    var viewControllers: [UIViewController]
    @Environment(\.splitViewPreferredDisplayMode) var preferredDisplayMode: UISplitViewController.DisplayMode

    func makeUIViewController(context: Context) -> UISplitViewController {
        return UISplitViewController()
    }

    func updateUIViewController(_ splitController: UISplitViewController, context: Context) {
        splitController.preferredDisplayMode = preferredDisplayMode
        splitController.viewControllers = viewControllers
    }
}

struct PreferredDisplayModeKey : EnvironmentKey {
    static var defaultValue: UISplitViewController.DisplayMode = .automatic
}

extension EnvironmentValues {
    var splitViewPreferredDisplayMode: UISplitViewController.DisplayMode {
        get { self[PreferredDisplayModeKey.self] }
        set { self[PreferredDisplayModeKey.self] = newValue }
    }
}

extension View {
    /// Sets the preferred display mode for SplitView within the environment of self.
    func splitViewPreferredDisplayMode(_ mode: UISplitViewController.DisplayMode) -> some View {
        self.environment(\.splitViewPreferredDisplayMode, mode)
    }
}
Run Code Online (Sandbox Code Playgroud)

然后使用它:

SplitView(master: {
            MasterView()
        }, detail: {
            DetailView()
        }).splitViewPreferredDisplayMode(.allVisible)
Run Code Online (Sandbox Code Playgroud)

在 iPad 上,它可以工作。但是有一个问题(也许更多……)。这种方法会破坏 iPhone 上的导航,因为 MasterView 和 DetailView 都有它们的 NavigationView。

更新: 最后,在 Xcode 11.4 beta 2 中,他们在导航栏中添加了一个按钮,指示隐藏的主视图。