当尝试重新访问之前点击的NavigationLink时,SwiftUI中的NavigationLink会冻结。

11

我正在设计一个包含检索JSON数据和在文件浏览器类型视图中显示检索到的项目列表功能的应用程序。在此视图中,用户应该能够点击文件夹以深入了解文件树,或者点击文件以查看有关该文件的一些元数据。

我发现,虽然这个功能正在工作,但当我单击文件或文件夹,然后返回并再次单击它时,导航链接不会触发,直到我单击其他导航链接之前,我就一直停留在该视图上。

以下是展示此问题的GIF。

Double Tap bug

如图所示,当我单击BlahBlah时,我正在激活NavigationLink并跳转到BlahBlah,然后当我导航回来并尝试重新导航到BlahBlah时,它变成灰色,注册我单击了它...但是从未将我传送到那里。单击TestFile可以解决此问题,并允许我导航回BlahBlah。

列表项由以下结构体创建:

private struct FileCell{
    var FileName: String
    var FileType: String
    var FileID: String = ""
    var isContainer: Bool
}

private struct constructedCell: View{

    var FileType: String
    var FileName: String
    var FileID: String

    var body: some View {
        return
            HStack{
                VStack(alignment: .center){
                    Image(systemName: getImage(FileType: FileType)).font(.title).frame(width: 50)
                }
                Divider()
                VStack(alignment: .leading){
                    Text(FileName).font(.headline)
                        .multilineTextAlignment(.leading)
                    Text(FileID)
                        .font(.caption)
                        .multilineTextAlignment(.leading)
                }
        }
    }
}

并通过以下导航链接调用视图

List(cellArray, id: \.FileID) { cell in
                if (cell.isContainer) {
                    NavigationLink(destination: FileView(path: "/\(cell.FileID)", displaysLogin: self.$displaysLogin).navigationBarTitle(cell.FileName)){
                        constructedCell(FileType: cell.FileType, FileName: cell.FileName, FileID: cell.FileID)
                    }
                } else {
                    NavigationLink(destination: DetailView(FileID: cell.FileID).navigationBarTitle(cell.FileName)){
                        constructedCell(FileType: cell.FileType, FileName: cell.FileName, FileID: cell.FileID)
                    }
                }
            }

我的NavigationView在上面的视图中初始化(应用程序有一个选项卡视图),代码如下:

TabView(selection: $selection){
               NavigationView{
                    FileView(displaysLogin: self.$displaysLogin)
                        .navigationBarTitle("Home", displayMode: .inline)
                        .background(NavigationConfigurator { nc in
                            nc.navigationBar.barTintColor = UIColor.white
                            nc.navigationBar.titleTextAttributes = [.foregroundColor : UIColor.black]
                        })
                }
                .font(.title)
                .tabItem {
                    VStack {
                        Image(systemName: "folder.fill")
                        Text("Files")
                    }
                }
                .tag(0)
}

NavigationConfigurator是我用来处理navigationBar颜色的结构体。它设置如下:

struct NavigationConfigurator: UIViewControllerRepresentable {
    var configure: (UINavigationController) -> Void = { _ in }

    func makeUIViewController(context: UIViewControllerRepresentableContext<NavigationConfigurator>) -> UIViewController {
        UIViewController()
    }
    func updateUIViewController(_ uiViewController: UIViewController, context: UIViewControllerRepresentableContext<NavigationConfigurator>) {
        if let nc = uiViewController.navigationController {
            self.configure(nc)
        }
    }

}

我不认为我的NavigationConfigurator导致了这个问题?在应用程序中,其他navigationLinks也会出现这个bug,但在FileBrowser视图中展示它是最容易的。

这可能是SwiftUI的一个bug吗?如果是,有谁知道解决方法吗?如果不是,那我做错了什么?


我不是太确定,但你是否应该将“NavigationLink”包装在“NavigationView”内,并从“FileView”中移除“NavigationView”?我在这里看到过一些这样做的示例。 - gi097
除非我误解了你的意思,否则这就是我正在做的事情。NavigationLink位于FileView内部,而FileView又被包装在NavigationView中,因此NavigationLink被包装在NavigationView内部。 - Vapidant
请提供一个最小可运行的项目。我无法复现这个问题,所以很可能不是SwiftUI的一个bug。 - Mojtaba Hosseini
你能提供完整的源代码,这样我就可以解决你的问题。 - Hardik Bar
你是如何准备 cellArray 的? - E.Coms
显示剩余2条评论
1个回答

6

我也遇到了同样的问题 - 试试这个。我认为这是一个hack,当swiftUI中的bug得到修复后就可以移除。

struct ListView: View {
@State private var destID = 0
...
var body: some View {
...
  NavigationLink(destination: FileView(path: "/\(cell.FileID)", displaysLogin: self.$displaysLogin)
   .navigationBarTitle(cell.FileName) 
   .onDisappear() { self.destID = self.destID + 1 }
  ){
   constructedCell(FileType: cell.FileType, FileName: cell.FileName, FileID: cell.FileID) 
  }.id(destID)

基本上,在某些情况下(iOS 13.3-Simulator?),当目标视图从导航堆栈中移除时,NavigationLink未被重置。作为解决方法,我们需要重新生成导航链接。这就是更改id所做的。这纠正了我的问题。
然而,如果您有链接链接到另一个链接列表的导航链接,那么这个解决方案将产生副作用。在第二次尝试显示最后一个视图时,堆栈会返回到原点。

这个 bug 在最新的 IOS 版本中已经修复。我将其标记为正确答案,因为它解决了问题,但是这不应该成为问题。我也喜欢你对问题的解释。谢谢。 - Vapidant
当你说最新的iOS版本时,是指13.4还是测试版? - Ricardo Alves
我也想知道。哪个版本是正确的?我有13.3(这是目前最新的iOS版本),但问题仍然存在。 - mallow
我相信这个 bug 出现在 IOS 13.3 beta 版本中,但已经在 IOS 13.3 Beta 4 中修复了。 - Vapidant
在iOS 16.1中有类似的问题。使用这种方法可以解决它。我使用.id(UUID())来确保它始终是唯一的。 - ngb

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接