从SwiftUI的详细信息视图中删除列表中的最后一项不会弹出详细信息视图

时间:2020-08-25 09:14:16

标签: ios swift swiftui swiftui-list swiftui-navigationlink

我正在开发一个应用程序,当从详细信息视图中删除列表中的最后一项时,遇到了List和NavigationLink的奇怪行为。我使用的是iOS 13和Xcode 11,我制作了一个简化的版本来重现此行为:

import SwiftUI

struct ListView: View {
    @State private var content = [Int](0..<10) {
        didSet {
            print(content)
        }
    }

    var body: some View {
        NavigationView {
            List(content, id: \.self) { element in
                NavigationLink(
                    destination: DetailView(
                        remove: {
                            DispatchQueue.global(qos: .userInitiated).asyncAfter(deadline: .now() + 1) { // Asynchronous network request
                                DispatchQueue.main.async {
                                    self.content.removeAll { $0 == element } // When request was successfull remove element from list
                                }
                            }
                        }
                    )
                ) {
                    Text("Element #\(element)")
                }
            }
        }
    }
}

struct DetailView: View {

    let remove: () -> Void

    init(remove: @escaping () -> Void) {
        self.remove = remove
    }

    var body: some View {
        VStack {
            Text("Hello world!")

            Button(
                action: {
                    self.remove()
                }
            ) {
                Image(systemName: "trash.circle")
                    .imageScale(.large)
            }
        }
    }
}

要重建错误,请选择列表中的最后一项,然后按垃圾桶将其删除。您可能会注意到,该视图并没有像列表中的其他项一样消失。但是,如果您按回去,该列表将正确删除最后一项。此gif中也显示了这一点。按下垃圾桶时,列表的状态更改会打印到控制台上。

我注意到删除特定项目似乎不是问题,因为删除随机项目时也会发生。如果我删除所选项目并在末尾添加新项目,则它可以正常工作。因此,这可能是由于缩小数组大小引起的。

我还找到了几种解决方法。就像使用.id(UUID())修改NavigationView一样,但这会删除动画。另一种解决方案是使用PresentationMode关闭视图,然后消失,从列表中删除该项目,但我宁愿使用其他解决方案。

要查看它是否与iOS 13或Xcode 11相关,我在最新的beta版本的iOS 14和Xcode 12(当前为beta 5)上对其进行了测试。在这里,详细信息视图不会与任何选定项一起消失。

有人有没有遇到过这个问题,或者至少可以解释为什么会这样?

编辑:添加了模拟网络请求以更好地说明特定问题。

1 个答案:

答案 0 :(得分:0)

SwiftUI在那儿表现得有些奇怪,我想...

您可以明确地告诉SwiftUI关闭DetailView。为此,您需要对DetailView进行一些修改:

struct DetailView: View {
    @Environment(\.presentationMode) var presentationMode
    
    let remove: () -> Void
    
    init(remove: @escaping () -> Void) {
        self.remove = remove
    }
    
    var body: some View {
        VStack {
            Text("Hello world!")
            
            Button(
                action: {
                    self.remove()
                    self.presentationMode.wrappedValue.dismiss()
                }
            ) {
                Image(systemName: "trash.circle")
                    .imageScale(.large)
            }
        }
    }
}

(另请参见:iOS SwiftUI: pop or dismiss view programmatically

对我来说,即使是最后一行,这似乎也可行。