【问题标题】:Sidebar with different columns in SwiftUISwiftUI 中具有不同列的侧边栏
【发布时间】:2020-07-19 09:40:27
【问题描述】:

我正在使用 SwiftUI 2 附带的新侧边栏以及在具有三列的大屏幕中导航的可能性。可以在此处找到有关其工作原理的示例:https://www.hackingwithswift.com/quick-start/swiftui/how-to-add-a-sidebar-for-ipados

它工作正常,但我想向前迈出一步,在我的主菜单中设置一些选项,显示三列,但其他选项只有两列。

这里是一些演示代码的示例。

import SwiftUI

struct ContentView: View {
    var body: some View{
        NavigationView{
            List{
                Section(header: Text("Three columns")){
                    NavigationLink(
                        destination: ItemsView(),
                        label: {
                            Label("Animals",systemImage: "tortoise")
                        })
                    NavigationLink(
                        destination: ItemsView(),
                        label: {
                            Label("Animals 2",systemImage: "hare")
                        })
                }
                Section(header: Text("Two columns")){
                    NavigationLink(
                        destination: Text("I want to see here a single view, without detail"),
                        label: {
                            Label("Settings",systemImage: "gear")
                        })
                    NavigationLink(
                        destination: Text("I want to see here a single view, without detail"),
                        label: {
                            Label("Settings 2",systemImage: "gearshape")
                        })
                }
            }
            .listStyle(SidebarListStyle())
            .navigationBarTitle("App Menu")
            
            ItemsView()
            DetailView(animal: "default")
            
        }
    }
}

struct ItemsView: View{
    let animals = ["Dog", "Cat", "Lion", "Squirrel"]
    var body: some View{
        List{
            ForEach(animals, id: \.self){ animal in
                NavigationLink(
                    destination: DetailView(animal: animal)){
                    Text(animal)
                }
            }
        }
        .listStyle(PlainListStyle())
        .navigationTitle("Animals")
    }
}

struct DetailView: View{
    var animal: String
    var body: some View{
        VStack{
            Text("????")
                .font(.title)
                .padding()
            Text(animal)
        }
    }
}
struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
            .previewLayout(.sizeThatFits)
    }
}

如果您在 iPad Pro(12.9 英寸)中以横向模式运行代码,您可以看到树列。首先是应用程序菜单(侧边栏)。如果您单击前两个选项之一(动物和动物 2),您可以看到动物列表(第二列),当您单击某些动物时,您会到达第三列(详细视图)。 但是,当我单击菜单的最后两个选项(设置和设置 2)时,我希望只有两列。任何线索如何实现它?

如果未选择菜单中的某些第一个选项(使用 NavigationLink 中的 selected 参数),我尝试隐藏该部分,但没有运气。似乎不可能(或者我不知道)知道在侧边栏中选择了哪个选项。

欢迎提出任何想法!

【问题讨论】:

  • 我有一个类似的问题,并通过创建两个 NavigationViews 来解决它:一个有两个条目,一个有三个。这些 NavigationView 由 if-then-else 嵌入,这取决于侧边栏的当前选择。效果很好...
  • 感谢@Hardy,您的解决方案是一个很好的解决方法,但它不能 100% 正常工作。显示选择的选项时出现问题,在某些情况下,返回按钮无法按预期工作。我联系了 Apple 支持,但该功能不受官方支持。希望在下一个 SwiftUI 大版本中得到支持。
  • @jarnaez,你知道这个功能是否包含在 SwiftUI 3.0 中吗?能够根据主菜单选择在 2 或 3 列之间进行切换将是非常棒的。
  • 嗨@Peanutsmasher,我暂时没有时间检查 SwiftUI 3 中的所有新功能和更改,但是从我所做的快速阅读中,我没有看到任何关于此功能的信息 :(

标签: swiftui sidebar


【解决方案1】:

我花了几天时间才弄明白。

在不同的 iPad 设备和多任务模式下测试,一切正常。(iOS14+,尚未在 iOS13 上测试)

小例子:

extension UISplitViewController {
    open override func viewDidLoad() {
        super.viewDidLoad()
        self.show(.primary) // show sidebar, this is the key, toke me days to find this...
        self.showsSecondaryOnlyButton = true
    }
}

struct ContentView: View {
    @State var column: Int = 3
    var body: some View {
        switch column {
        case 3: // Triple Column
            NavigationView {
                List {
                    HStack {
                        Text("Triple")
                    }
                    .onTapGesture {
                        column = 3
                    }
                    HStack {
                        Text("Double")
                    }
                    .onTapGesture {
                        column = 2
                    }
                }
                Text("Supplementary View")
                Text("Detail View")
            }
        default: // Double Column
            NavigationView {
                List {
                    HStack {
                        Text("Triple")
                    }
                    .onTapGesture {
                        column = 3
                    }
                    HStack {
                        Text("Double")
                    }
                    .onTapGesture {
                        column = 2
                    }
                }
                Text("Supplementary View")
            }
        }
    }
}

我的另一个答案:设置侧边栏默认选中项。

结合这两个解决方案,我已经构建了一个2&3列共存样式的应用程序。

SwiftUI, selecting a row in a List programmatically

【讨论】:

    【解决方案2】:

    这是一个使用自定义ViewModifier 的解决方案。它适用于 iOS 14.2、15.0 和 15.2。由于您使用的是SidebarListStyleLabel,因此我没有测试以前的版本。

    测试项目:

    enum Item: Hashable {
        case animals, animals2, settings, settings2
    
        static var threeColumns = [Item.animals, .animals2]
        static var twoColumns = [Item.settings, .settings2]
    
        var title: String {
            switch self {
            case .animals:
                return "animals"
            case .animals2:
                return "animals2"
            case .settings:
                return "settings"
            case .settings2:
                return "settings2"
            }
        }
    
        var systemImage: String {
            switch self {
            case .animals:
                return "tortoise"
            case .animals2:
                return "hare"
            case .settings:
                return "gear"
            case .settings2:
                return "gearshape"
            }
        }
    }
    
    struct ContentView: View {
    
        @State var selectedItem: Item?
    
        var body: some View {
            NavigationView {
                List {
                    Section(header: Text("Three columns")) {
                        ForEach(Item.threeColumns, id: \.self) { item in
                            NavigationLink(tag: item, selection: $selectedItem) {
                                ItemsView()
                            } label: {
                                Label(item.title.capitalized, systemImage: item.systemImage)
                            }
                        }
                    }
                    Section(header: Text("Two columns")) {
                        ForEach(Item.twoColumns, id: \.self) { item in
                            NavigationLink(
                                destination: Text("I want to see here a single view, without detail"),
                                label: {
                                    Label(item.title, systemImage: item.systemImage)
                                })
                        }
                    }
                }
                .listStyle(SidebarListStyle())
                .navigationBarTitle("App Menu")
            }
        }
    }
    
    struct ItemsView: View {
        let animals = ["Dog", "Cat", "Lion", "Squirrel"]
        var body: some View {
            List {
                ForEach(animals, id: \.self) { animal in
                    NavigationLink(
                        destination: DetailView(animal: animal)) {
                            Text(animal)
                        }
                }
            }
            .listStyle(PlainListStyle())
            .navigationTitle("Animals")
        }
    }
    
    struct DetailView: View {
        var animal: String
        var body: some View {
            VStack {
                Text("?")
                    .font(.title)
                    .padding()
                Text(animal)
            }
        }
    }
    struct ContentView_Previews: PreviewProvider {
        static var previews: some View {
            ContentView()
                .previewLayout(.sizeThatFits)
        }
    }
    
    private struct ColumnModifier: ViewModifier {
        let item: Item?
    
        func body(content: Content) -> some View {
            if item == .settings || item == .settings2 {
                content
                EmptyView()
            } else {
                content
                EmptyView()
                DetailView(animal: "default")
            }
        }
    }
    
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-10-26
      • 1970-01-01
      • 2019-10-27
      • 2020-10-26
      • 1970-01-01
      • 2020-11-11
      • 2020-04-15
      • 1970-01-01
      相关资源
      最近更新 更多