【问题标题】:iOS 15: Navigation link popping out, againiOS 15:导航链接再次弹出
【发布时间】:2021-10-27 20:40:48
【问题描述】:

在过去的几个月里,许多开发人员报告说 NavigationLinks 意外弹出,并且已经发布了一些解决方法,包括添加另一个空链接和将 .navigationViewStyle(StackNavigationViewStyle()) 添加到导航视图。

这里我想演示另一种NavigationLink意外弹出的情况:

当有两个级别的子视图,即parentView > childLevel1 > childLevel2,childLevel2修改childLevel1,那么,回去之后从2级到1级,弹出1级并显示parentView。

我已经提交了错误报告,但此后没有收到苹果的消息。已知的解决方法似乎都不起作用。有人知道该怎么做吗?等 iOS 15.1 吧?

以下是我的代码(iPhone 应用程序)。在父视图中,有一个从中获取订单的人员列表。在 childLevel1 中,显示了来自特定人员的所有订单。每个订单都可以通过点击来修改,这会导致childLevel2。在 childLevel2 中,有几个选项可用(为简洁起见,这里只显示一个),这就是用户应该通过“

import SwiftUI

struct Person: Identifiable, Hashable {
    let id: Int
    let name: String
    var orders: [Order]
}

struct Pastry: Identifiable, Hashable {
    let id: Int
    let name: String
}

struct Order: Hashable {
    var paId: Int
    var n: Int // used only in the real code
}

class Data : ObservableObject {
    
    init() {
        pastries = [
            Pastry(id: 0, name: "Prezel"),
            Pastry(id: 1, name: "Donut"),
            Pastry(id: 2, name: "bagel"),
            Pastry(id: 3, name: "cheese cake"),
        ]

        persons = [
            Person(id: 0, name: "Alice", orders: [Order(paId: 1, n: 1)]),
            Person(id: 1, name: "Bob", orders: [Order(paId: 2, n: 1), Order(paId: 3, n: 1)])
        ]
        
        activePersonsIds = [0, 1]
    }
    
    @Published var activePersonsIds: [Int] = []
    @Published var persons: [Person] = []
    @Published var pastries: [Pastry]
    @Published var latestOrder = Order(paId: 0, n: 1)
            
    lazy var pastryName: (Int) -> String = { (paId: Int) -> String in
        if self.pastries.first(where: { $0.id == paId }) == nil {
            return "undefined pastryId " + String(paId)
        }
        return self.pastries.first(where: { $0.id == paId })!.name
    }
    
    var activePersons : [Person] {
        return activePersonsIds.compactMap {id in persons.first(where: {$0.id == id})}
    }
}

@main
struct Bretzel_ProApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

struct ContentView: View {
    @Environment(\.colorScheme) var colorScheme
    @StateObject var data = Data()
    
    var body: some View {
        TabView1(data: data)
        // in the real code, there are more tabs
    }
}

struct TabView1: View {
    @StateObject var data: Data

    var body: some View {
            NavigationView {
                List {
                    ForEach(data.activePersons, id: \.self) { person in
                        NavigationLink(
                            destination: EditPerson(data: data, psId: person.id),
                            label: {
                                VStack (alignment: .leading) {
                                    Text(person.name)
                                }
                            }
                        )
                    }
                }
                .listStyle(PlainListStyle())
                .navigationTitle("Orders")
            }
            .navigationViewStyle(StackNavigationViewStyle())
    }
}

struct EditPerson: View {
    @ObservedObject var data: Data
    
    var psId: Int
    
    var body: some View {
        let pindex: Int = data.persons.firstIndex(where: { $0.id == psId })!
        let p: Person = data.persons[pindex]

        List() {
            ForEach (0...p.orders.count-1, id: \.self) { loop in
                Section(header:
                            HStack() {
                                Text("BESTELLUNG " + String(loop+1))
                            }
                ) {
                    EPSubview1(data: data, psId: psId, loop: loop)
                }
            }
        }.navigationTitle(p.name)
        .listStyle(InsetGroupedListStyle())
    }
}

struct EPSubview1: View {
    @ObservedObject var data: Data
    var psId: Int
    var loop: Int
    
    var body: some View {
        let pindex: Int = data.persons.firstIndex(where: { $0.id == psId })!
        let p: Person = data.persons[pindex]
        let o1: Order = p.orders[loop]

        NavigationLink(
            destination: SelectPastry(data: data)
                .onAppear() {
                    data.latestOrder.paId = o1.paId
                }
                .onDisappear() {
                    data.persons[pindex].orders[loop].paId = data.latestOrder.paId
                },
            label: {
                VStack(alignment: .leading) {
                    Text(String(o1.n) + " x " + data.pastryName(o1.paId))
                }
            }
        )
    }
}

struct SelectPastry: View {
    @ObservedObject var data : Data
    
    var body: some View {

        VStack {
            List {
                ForEach(data.pastries, id: \.self) {pastry in
                    Button(action: {
                        data.latestOrder.paId = pastry.id
                    }) {
                        Text(pastry.name)
                            .foregroundColor(data.latestOrder.paId == pastry.id ? .primary : .secondary)
                    }
                }
            }.listStyle(PlainListStyle())
        }
    }
}

【问题讨论】:

    标签: swiftui swiftui-navigationlink


    【解决方案1】:

    问题是你的ForEach。尽管Person 符合Identifiable 这一事实,但您使用\.self 来识别数据。因此,每当Person 的某个方面发生变化时,self 的值也会发生变化。

    相反,只需使用此表单,它使用由Identifiable 提供的id

    ForEach(data.activePersons) { person in
    

    相当于:

    ForEach(data.activePersons, id: \.id) { person in
    

    【讨论】:

    • 哇,jnpdx,你是我的英雄!事实上,这就是解决方案,虽然我不知道你是如何在我发布我的代码几分钟后发现的。谢谢!
    • 当我看到self 被用作id 时,我有了一个很好的想法——这是一个在 SO 上经常出现的问题,在各种不同的情况。
    猜你喜欢
    • 2021-12-28
    • 1970-01-01
    • 2021-11-05
    • 1970-01-01
    • 2021-12-24
    • 2015-09-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多