web-dev-qa-db-fra.com

NavigationLink se bloque lorsque vous essayez de revisiter NavigationLink cliqué précédemment dans SwiftUI

Je conçois une application qui inclut la fonction de récupération de données JSON et d'affichage d'une liste d'éléments récupérés dans une vue de type FileBrowser. Dans cette vue, un utilisateur devrait pouvoir cliquer sur un dossier pour plonger plus profondément dans l'arborescence des fichiers ou cliquer sur un fichier pour afficher des métadonnées sur ledit fichier.

J'ai observé que pendant que cela fonctionne, lorsque je clique sur un fichier ou un dossier, puis que je reviens en arrière et que je clique à nouveau dessus, le NavigationLink n'est pas déclenché et je suis bloqué sur la vue jusqu'à ce que je clique sur un autre NavigationLink.

Voici un gif illustrant ce problème.

Double Tap bug

Comme on le voit ici, quand je clique sur BlahBlah, j'active le NavigationLink et je suis amené à BlahBlah, puis quand je reviens en arrière et essaye de renaviguer vers BlahBlah, il devient gris, enregistrant que j'ai cliqué dessus ... mais ne m'y transporte jamais . Cliquer sur TestFile corrige cela et me permet de revenir à BlahBlah.

Les éléments de liste sont créés avec les structures suivantes

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)
                }
        }
    }
}

et appelé en vue avec navigationLinks comme suit

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)
                    }
                }
            }

Mon NavigationView est initialisé dans la vue ci-dessus (l'application a une vue d'onglet) comme suit

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)
}

Le NavigationConfigurator est une structure que j'utilise pour gérer la couleur de la barre de navigation. Il est configuré comme ça

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)
        }
    }

}

Je ne pense pas que ma NavigationConfigurator soit à l'origine de cela? Ce bogue se produit également dans d'autres liens de navigation de l'application, mais il était plus facile de le démontrer ici dans la vue FileBrowser.

Cela pourrait être un bug dans SwiftUI? Si c'est le cas, quelqu'un connaît-il un moyen de contourner ce problème? Si ce n'est pas le cas, que fais-je de mal?

10
Vapidant

Eu le même problème - essayez ceci. J'appellerais cela un hack à supprimer lorsque le bogue dans swiftUI est corrigé.

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)

Essentiellement, il semble que dans certaines circonstances (iOS 13.3 - Simulator?) Le NavigationLink n'est pas réinitialisé lorsque la vue de destination est supprimée de la pile de navigation. En guise de solution, nous devons régénérer le lien de navigation. C'est ce que fait le changement d'identifiant. Cela a corrigé mon problème.

Cependant, si vous avez des liens de navigation chaînés, c'est-à-dire un lien menant à une autre liste de liens, cette solution créera des effets secondaires; la pile revient à l'origine à la deuxième tentative pour afficher la dernière vue.

5
VJK