【问题标题】:SwiftUI - NavigationLink cell in a Form stays highlighted after detail popSwiftUI - 表单中的 NavigationLink 单元格在详细信息弹出后保持突出显示
【发布时间】:2021-01-04 02:39:57
【问题描述】:

在 iOS 14 中,NavigationLinks 在返回 Form 上下文后似乎不会被取消选择。 对于Form Pickers 和其他任何导致从列表中显示另一个View 的事物也是如此(为显示单元格提供突出显示的上下文)。

我在 iOS 13 中没有注意到这种行为。

一旦关闭另一个视图,是否有办法“取消选择”突出显示的行?

示例代码:

struct ContentView: View {

    var body: some View {
        Form {
            NavigationLink(destination: Text("Detail")) {
                Text("Link")
            } 
        }
    }

}

(不同)视觉示例:

【问题讨论】:

  • 这通常发生在您的导航堆栈中有多个 NavigationView 时。确保您的视图仅嵌入在一个 NavigationView 中。
  • 我遇到了完全相同的问题,但无法解决。另外,我只有一个 NavigationView @pawello2222
  • @leonboe1 检查我的回答是否有帮助!
  • @BradleyMackey 不幸的是,它对我没有帮助。它适用于一个页面,是的,但是我在页面 A 上有 NavigationLinks 通向页面 B,而在页面 B 上有通向另一个页面 C 等的导航链接。我不能多次使用 NavigationView。
  • 似乎是工作表的问题。见stackoverflow.com/questions/63945077/…

标签: ios swift swiftui uikit


【解决方案1】:

在我的情况下,当在我的 NavigationViewList/Form 之间使用任何 Viewcontent(例如 Text()、Image()、...)时,就会出现这种行为。

var body: some View {
    
    NavigationView {
        VStack {
            Text("This text DOES make problems.")
            List {
                NavigationLink(destination: Text("Doesn't work correct")) {
                    Text("Doesn't work correct")
                }
            }
        }
    }
}

将 Text() 放在 List 不会造成任何问题:

var body: some View {
    
    NavigationView {
        VStack {
            List {
                NavigationLink(destination: Text("Does work correct")) {
                    Text("Does work correct")
                }
            }
            Text("This text doesn't make problems.")
        }
    }
}

这绝对是 XCode 12 的错误。随着越来越多的人报告此问题,它会越早得到解决。

【讨论】:

  • 你能举个例子吗?我不太明白。
  • 通过一个简单的示例查看我的更新答案。 Text() 只是产生问题的一个例子。 Image() 和许多其他的具有相同的行为。
  • Apple 还没有修复它,是吗?
  • 很棒的发现,我也可以确认这种行为......应该是一个错误
  • Xcode 12.5 beta 3 仍然存在问题。就我而言,列表上方有一个 Picker View。
【解决方案2】:

我也遇到过这个问题,并相信我找到了我的问题的根本原因。

就我而言,我的结构如下:

struct Page1View: View {
    var body: some View {
        NavigationView {
            List {
                NavigationLink("Page 2", destination: Page2View())
            }
                .listStyle(GroupedListStyle())
                .navigationBarTitle("Page 1")
        }
    }
}

struct Page2View: View {
    var body: some View {
        List {
            NavigationLink("Page 3", destination: Text("Page 3"))
        }
            .listStyle(GroupedListStyle())
            .navigationBarTitle("Page 2")
    }
}

导航链接到第 3 页时会出现此问题。在控制台输出中,使用该链接时会显示此错误:

2021-02-13 16:41:00.599844+0000 App[59157:254215] [Assert] displayModeButtonItem is internally managed and not exposed for DoubleColumn style. Returning an empty, disconnected UIBarButtonItem to fulfill the non-null contract.

我发现我需要将.navigationViewStyle(StackNavigationViewStyle()) 应用于 NavigationView,这解决了问题。

struct Page1View: View {
    var body: some View {
        NavigationView {
            List {
                NavigationLink("Page 2", destination: Page2View())
            }
                .listStyle(GroupedListStyle())
                .navigationBarTitle("Page 1")
        }
            .navigationViewStyle(StackNavigationViewStyle())
    }
}

【讨论】:

  • 也为我解决了,感谢您的解决方案?
  • 这正是我所需要的!非常感谢!
  • 我已经有这个错误好几个星期了,你解决了,谢谢!
  • 修复了 displayModeButtonItem 的日志消息,但我的选择器在选择后仍然保持灰色。
【解决方案3】:

今天已经解决了这个问题半天,来到这篇文章帮助我理解如果TextButton 或其他位于NavigationView 和我的情况下为List 之间的东西会出现这个问题。我找到了适合我的解决方案。只需为该项目添加.zIndex().zIndex() 必须高于 List 尝试使用 Xcode 12.5

var body: some View {
    NavigationView {
        VStack {
            Text("This text DOES make problems.")
                .zIndex(1.0)
            List {
                NavigationLink(destination: Text("Doesn't work correct")) {
                    Text("Doesn't work correct")
                }
            }
        }
    }
}

【讨论】:

  • 这对我来说适用于 iOS 14.5 模拟器的 Xcode 12.5。
【解决方案4】:

我做了更多的修改,结果证明这是由于将UIHostingController 嵌套在UINavigationController 中并使用该导航控制器造成的。将导航堆栈更改为使用 SwiftUI NavigationView 解决了这个问题。

类似于@pawello2222 在问题 cmets 中所说的,我认为根本原因与使用外部 UINavigationController 时 SwiftUI 不理解正确的导航层次结构有关。

这只是解决此问题的一个实例,根据我的视图的结构,我在其他各种情况下仍会遇到此问题。

我已向 Apple 提交了问题报告 FB8705430,因此希望此问题能很快得到解决。

之前(破损):

struct ContentView: View {
    var body: some View {
        Form {
             NavigationLink(destination: Text("test")) {
                 Text("test")
             }
        }
    }
}

// (UIKit presentation context)
let view = ContentView() 
let host = UIHostingController(rootView: view)
let nav = UINavigationController(rootViewController: host)
present(nav, animated: true, completion: nil)

之后(工作):

struct ContentView: View {
    var body: some View {
        NavigationView {
            Form {
                NavigationLink(destination: Text("test")) {
                    Text("test")
                }
            }
        }
    }
}

// (UIKit presentation context)
let view = ContentView()
let host = UIHostingController(rootView: view)
present(host, animated: true, completion: nil)

【讨论】:

  • 只是确认它曾经在 iOS 13.7 上正常工作(并且仍然可以正常工作)。
  • 我有同样的问题,但不幸的是这不起作用,因为我的初始视图控制器是 UIKit 表视图,并且是 UINavigationController 的根视图控制器。选择一行时,我推送一个视图控制器,在其中创建一个 UIHostingController 的实例,包装我的 SwiftUI 表单并将其添加为子视图控制器。如果我给自己的表单提供自己的 NavigationView,我最终会得到来自 2 个导航控制器的 2 个导航栏。我尝试继承 UIHostingController 而不是实例化它,但它没有用。我希望有一个明确的解决办法。
  • UINavigationController 中的 SwiftUI 视图还有更多问题。例如导航标题和导航栏按钮在导航转换完成后会弹出,而不是像原生 UIKit ViewControllers 那样进行动画处理。这实质上意味着 SwiftUI 不能在混合 UIKit/SwiftUI 应用程序中使用,我决定再次将其撕掉并用常规 UIKit 替换它......
【解决方案5】:

这绝对是List 中的一个错误,目前,我的解决方法是通过更改 id 来刷新List,如下所示:

struct YourView: View {
    @State private var selectedItem: String?
    @State private var listViewId = UUID()

    var body: some View {
            List(items, id: \.id) {
                NavigationLink(destination: Text($0.id), 
                               tag: $0.id, 
                               selection: $selectedItem) {
                  Text("Row \($0.id)")
                }
            }
            .id(listViewId)
            .onAppear {
                if selectedItem != nil {
                    selectedItem = nil
                    listViewId = UUID()
                }
            }
    } 
}

我在此基础上做了一个修改器,你可以使用:

struct RefreshOnAppearModifier<Tag: Hashable>: ViewModifier {
    @State private var viewId = UUID()
    @Binding var selection: Tag?
    
    func body(content: Content) -> some View {
        content
            .id(viewId)
            .onAppear {
                if selection != nil {
                    viewId = UUID()
                    selection = nil
                }
            }
    }
}

extension View {
    func refreshOnAppear<Tag: Hashable>(selection: Binding<Tag?>? = nil) -> some View {
        modifier(RefreshOnAppearModifier(selection: selection ?? .constant(nil)))
    }
}

像这样使用它:

List { ... }
  .refreshOnAppear(selection: $selectedItem)

【讨论】:

  • 很好,感谢您将其提取到修饰符中。富有创意且超级有用。
【解决方案6】:

我设法通过将 id 添加到列表的不同组件、使用绑定和重置 .onDisappear 上的绑定来解决它

struct ContentView: View {
    @State var selection: String? = nil

    var body: some View {
        NavigationView {
            VStack {
                Text("Hello, world!")
                    .padding()
                List {
                    Section {
                        NavigationLink( destination: Text("Subscreen1"), tag: "link1", selection: $selection ) {
                            Text("Subscreen1")
                        }.onDisappear {
                            self.selection = nil
                        }
                        NavigationLink( destination: Text("Subscreen2"), tag: "link2", selection: $selection ) {
                            Text("Subscreen2")
                        }.onDisappear {
                            self.selection = nil
                        }
                    }.id("idSection1")
                }
                .id("idList")
            }
        }
    }
}

【讨论】:

  • 这个解决方案是最好的,应该是认可的答案。
  • .onDisappear { self.selection = nil } 实际上应该取消导航链接,如果 iOS 问题得到修复,那将是预期的行为
  • 他们似乎已经在 iOS 14.5 中修复了这个问题,将 .onDisappear 中的选择设置为 nil 会导致页面立即导航回来(取消导航链接)
  • 从 iOS14.5 开始,此解决方案不再有效。
【解决方案7】:

我也遇到过这个问题,它似乎与 here 提到的工作表有关。

我的解决方案是混合UITableView 捕捉选择,然后取消选择单元格。这样做的代码is here。希望这将在未来的 iOS 中得到解决。

【讨论】:

    【解决方案8】:

    .navigationViewStyle(StackNavigationViewStyle()) 添加到NavigationView 为我修复了它。

    在本帖推荐:https://developer.apple.com/forums/thread/660468

    【讨论】:

      【解决方案9】:

      遇到同样的问题。奇怪的是,完全相同的代码在 iOS13 中工作。 我遇到了一个简单列表的问题:

      struct TestList: View {
          let someArray = ["one", "two", "three", "four", "five"] 
          var body: some View {
              List(someArray, id: \.self) { item in 
                      NavigationLink(
                          destination: Text(item)) {
                          Text(item)
                      }.buttonStyle(PlainButtonStyle()) 
              }.navigationBarTitle("testlist") 
          }
      }
      

      这是嵌入在:

      struct ListControllerView: View {
          @State private var listPicker = 0
          var body: some View {
              NavigationView{
                  Group{
                      VStack{
                          Picker(selection: $listPicker, label: Text("Detailoverview")) {
                              Text("foo").tag(0)
                              Text("bar").tag(1)
                              Text("TestList").tag(2)
                          }
      

      这是在标签栏内。

      【讨论】:

        【解决方案10】:

        这是我在解决此列表问题之前一直使用的解决方法。使用 Introspect 库,我保存了 List 的 UITableView.reloadData 方法,并在它再次出现时调用它。

        import SwiftUI
        import Introspect
        
        struct MyView: View {
        
            @State var reload: (() -> Void)? = nil
        
            var body: some View {
                NavigationView {
                    List {
                        NavigationLink("Next", destination: Text("Hello"))
                    }.introspectTableView { tv in
                        self.reload = tv.reloadData
                    }.onAppear {
                        self.reload?()
                    }
                }
            }
        }
        

        【讨论】:

          猜你喜欢
          • 2010-09-17
          • 1970-01-01
          • 2021-04-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-07-31
          相关资源
          最近更新 更多