【问题标题】:Incomplete Swipe-back gesture causes NavigationPath mismanagement不完整的回扫手势导致 NavigationPath 管理不善
【发布时间】:2022-10-14 03:26:21
【问题描述】:

我正在下面的示例代码中寻找以下错误的解决方案。我尝试使用 SwiftUI 4 和 iOS 16.0 导航 API 变更集来实现导航器模式。

下面的示例将在 Xcode 14.0+ 中编译,如果在模拟器或具有 iOS 16.0 的设备中运行将产生我所描述的错误。我想知道这是缺乏知识还是平台错误。通过我的日志,我可以看到,当我用不完整的向后滑动手势引发错误时,导航路径的元素计数上升到 2,而实际上它应该在根处返回 0,并且在第一层只保留 1 个元素看法。

有没有办法可以更好地管理这种视图层次结构的路径?或者,这是一个平台级别的错误?

import SwiftUI

enum AppViews: Hashable {
    case kombuchaProductsView
    case coffeeProductsView
    case customerCartView
}

struct RootView: View {
    @StateObject var drinkProductViewModel = DrinkProductViewModel()
    
    var body: some View {
        NavigationStack(path: self.$drinkProductViewModel.navPath) {
            List {
                Section("Products") {
                    NavigationLink(value: AppViews.kombuchaProductsView) {
                        HStack {
                            Text("View all Kombuchas")
                            Spacer()
                            Image(systemName: "list.bullet")
                        }
                    }
                    NavigationLink(value: AppViews.coffeeProductsView) {
                        HStack {
                            Text("View all Coffees")
                            Spacer()
                            Image(systemName: "list.bullet")
                        }
                    }
                }
                Section("Checkout") {
                    NavigationLink(value: AppViews.customerCartView) {
                        HStack {
                            Text("Cart")
                            Spacer()
                            Image(systemName: "cart")
                        }
                    }
                }
            }
            .navigationDestination(for: AppViews.self) { appView in
                switch appView {
                    case .kombuchaProductsView:
                        KombuchaProductsView(drinkProductViewModel: self.drinkProductViewModel)
                    case .coffeeProductsView:
                        CoffeeProductsView(drinkProductViewModel: self.drinkProductViewModel)
                    case .customerCartView:
                        Text("Not implemented")
                }
            }
        }
        .onAppear {
            print("RootView appeared.")
            print("Nav stack count: \(self.drinkProductViewModel.navPath.count) (RootView)")
        }
    }
}

struct KombuchaProductsView: View {
    @State var drinkProductViewModel: DrinkProductViewModel
    var body: some View {
        ScrollView {
            VStack(spacing: 16) {
                ForEach(drinkProductViewModel.kombuchaProducts, id: \.self) { kombucha in
                    NavigationLink {
                        KombuchaView(
                            drinkProductViewModel: self.drinkProductViewModel,
                            kombucha: kombucha
                        )
                    } label: {
                        HStack {
                            Text(kombucha.name)
                            Spacer()
                            Text("$\(kombucha.price)")
                            Image(systemName: "chevron.right")
                                .foregroundColor(.gray)
                        }
                    }
                    Divider()
                }
                .padding()
            }
        }
        .navigationTitle("Kombucha Selection")
        .onAppear {
            print("KombuchaProductsView appeared.")
            print("Nav stack count: \(self.drinkProductViewModel.navPath.count) (KombuchaProductsView)")
        }
        .onDisappear {
            print("KombuchaProductsView disappeared")
        }
    }
}

struct CoffeeProductsView: View {
    @State var drinkProductViewModel: DrinkProductViewModel
    var body: some View {
        ScrollView {
            VStack(spacing: 16) {
                ForEach(drinkProductViewModel.coffeeProducts, id: \.self) { coffee in
                    NavigationLink {
                        CoffeeView(
                            drinkProductViewModel: self.drinkProductViewModel,
                            coffee: coffee
                        )
                    } label : {
                        HStack {
                            Text(coffee.name)
                            Spacer()
                            Text("$\(coffee.price)")
                            Image(systemName: "chevron.right")
                                .foregroundColor(.gray)
                        }
                    }
                    Divider()
                }
                .padding()
            }
        }
        .navigationTitle("Coffee Selection")
        .onAppear {
            print("CoffeeProductsView appeared")
            print("Nav stack count: \(self.drinkProductViewModel.navPath.count) (CoffeeProductsView)")
        }
        .onDisappear {
            print("CoffeeProductsView disappeared")
        }
    }
}

struct KombuchaView: View {
    @ObservedObject var drinkProductViewModel: DrinkProductViewModel
    @State var kombucha: Kombucha
    var body: some View {
        VStack {
            Text("Price:")
                .font(.title)
            Text("\(kombucha.price)")
                .font(.callout)
        }
        .navigationTitle(kombucha.name)
        .onAppear {
            print("Nav stack count: \(self.drinkProductViewModel.navPath.count) (KombuchaView)")
        }
    }
}

struct CoffeeView: View {
    @ObservedObject var drinkProductViewModel: DrinkProductViewModel
    @State var coffee: Coffee
    var body: some View {
        VStack {
            Text("Price:")
                .font(.title)
            Text("\(coffee.price)")
                .font(.callout)
        }
        .navigationTitle(coffee.name)
        .onAppear {
            print("Nav stack count: \(self.drinkProductViewModel.navPath.count) (CoffeeView)")
        }
    }
}

对于那些对精确编译我的示例感兴趣的人,下面是我的模拟 ViewModel(它只是保存静态数据 - 它纯粹是为了这个探索而构建的):

class DrinkProductViewModel: ObservableObject {
    
    @Published var navPath = NavigationPath()
    
    @Published var customerCart = [Any]()
    
    @Published var kombuchaProducts = [Kombucha]()
    
    @Published var coffeeProducts = [Coffee]()
    
    init() {
        // Let's ignore networking, and assume a bunch of static data
        self.kombuchaProducts = [
            Kombucha(name: "Ginger Blast", price: 4.99),
            Kombucha(name: "Cayenne Fusion", price: 6.99),
            Kombucha(name: "Mango Tango", price: 4.49),
            Kombucha(name: "Clear Mind", price: 5.39),
            Kombucha(name: "Kiwi Melon", price: 6.99),
            Kombucha(name: "Super Berry", price: 5.99)
        ]
        self.coffeeProducts = [
            Coffee(name: "Cold Brew", price: 2.99),
            Coffee(name: "Nitro Brew", price: 4.99),
            Coffee(name: "Americano", price: 6.99),
            Coffee(name: "Flat White", price: 5.99),
            Coffee(name: "Espresso", price: 3.99)
        ]
    }
    
    func addToCustomerCart() {
        
    }
    
    func removeFromCustomerCart() {
        
    }
}

请注意:通过不完整的滑动手势,我的意思是用户开始从前缘拖动屏幕,然后按住它,然后将其返回到其起始位置并释放它,这样用户就不会离开,而是保持在当前视图中背部。然后返回父视图(不是根视图)将导致导航链接失效。

您可以通过未能从康普茶或咖啡详细视图(最深的子视图)完成向后滑动手势来观察我描述的错误,然后返回到产品列表视图之一并尝试单击导航之一链接(应该是死的)。

返回根视图通常会在运行时清除此场景并恢复 NavigationLink 功能。

【问题讨论】:

    标签: swiftui drag swiftui-navigationlink ios16 swiftui-navigationstack


    【解决方案1】:

    可以在更简单的场景中重现的非常奇怪的行为。 看起来这个“半”手势在 NavStack 中弄乱了一些东西。

    我还要注意,在

    struct CoffeeProductsView: View {
        @State var drinkProductViewModel: DrinkProductViewModel
    

    @State 对我来说没有多大意义,而是想成为@ObservedObject,但它对这个问题没有影响。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-03-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多