ios SwiftUI复杂导航数据模型设计

alen0pnh  于 2023-01-18  发布在  iOS
关注(0)|答案(1)|浏览(107)

在iOS 16中,SwiftUI引入了新的导航API,要求导航状态由数据驱动,因此在采用新的导航API之前,需要设计导航数据模型。
我遇到过一个案例,我发现在iOS 16中为SwiftUI导航API设计数据模型相当困难。为了清楚地说明这个案例,我将提供以下场景。
该应用程序包含两个主要部分:水果店食谱,在水果店中,用户可以浏览和购买不同种类的水果;在食谱中,用户可以浏览在线食谱来制作一些饮料。
这两个板块都有一些比较复杂的导航系统,在水果店板块,用户从首页开始浏览一些水果的详细信息页面,在那里他可能会再次导航到一些水果的分类页面等,在食谱板块也是如此,总之,这两个板块的导航系统都不能用一个单一的类型来分类。
我希望使用三列设计,即NavigationSplitView,如下图所示。

我读过苹果的NavigationCookbook演示,但它没有解决我的问题。它的详细页面只有一种类型,所以使用单个值来控制详细页面将是一个优雅的解决方案。然而,这并不适用于我的情况,因为我的详细页面有多种类型。
我想知道是否有一个简单的解决方案来解决这个问题,这对在大规模项目中采用SwiftUI的人来说会非常有用。

ffscu2ro

ffscu2ro1#

这看起来很简单。使用初始化器

NavigationSplitView(sidebar: () -> Sidebar, content: () -> Content, detail: () -> Detail)

你只需要跟踪侧边栏的选择。在content中使用NavigationLink s,NavigationSplitView处理显示正确的细节视图。

struct ContentView: View {
        
    @State private var sidebarSelection: SidebarType?
    
    var body: some View {
        NavigationSplitView {
            List(SidebarType.allCases, id: \.self, selection: $sidebarSelection) { type in
                Text(type.name)
            }
        } content: {
            switch sidebarSelection {
            case .recipes:
                List(Recipe.allCases) { recipe in
                    NavigationLink(recipe.name) {
                        Text("Selected: \(recipe.name)")
                    }
                }
            case .fruits:
                List(Fruit.allCases) { fruit in
                    NavigationLink(fruit.name) {
                        Text("Selected: \(fruit.name)")
                    }
                }
            default:
                Text("Select something")
            }
        } detail: {
            switch sidebarSelection {
            case .recipes:
                Text("Select a recipe")
            case .fruits:
                Text("Select a fruit")
            default:
                EmptyView()
            }
        }
    }
}

struct Recipe: CaseIterable, Identifiable, Hashable {
    let id = UUID()
    let name: String
    static let allCases: [Recipe] = (1...9).map { Recipe(name: "Recipe \($0)")}
}

struct Fruit: CaseIterable, Identifiable, Hashable {
    let id = UUID()
    let name: String
    static let allCases: [Fruit] = (1...9).map { Fruit(name: "Fruit \($0)")}
}

enum SidebarType: CaseIterable, Identifiable {
    var id: Self { self }
    case recipes, fruits
    var name: String {
        switch self {
        case .recipes: return "Recipes"
        case .fruits: return "Fruit Store"
        }
    }
}

相关问题