【问题标题】:SwiftUI multiple NavigationLinks in Form/Sheet - entry stays highlighted表单/表格中的 SwiftUI 多个 NavigationLink - 条目保持突出显示
【发布时间】:2020-09-17 19:33:34
【问题描述】:

我遇到了 Xcode 12 / iOS 14 的问题。在带有 NavigationView 的工作表中使用多个 NavigationLink 会导致 NavigationLink 条目在返回页面后保持突出显示。这不仅是模拟器的问题。请参阅随附的 GIF:

有人知道如何解决这个问题吗?

类似问题:SwiftUI - NavigationLink cell in a Form stays highlighted after detail pop(但这不是这里的问题)。

struct ContentView: View {
    
    var body: some View {
        Text("")
            .sheet(isPresented: .constant(true), content: {
                NavigationView {
                    Form {
                        Section {
                            NavigationLink("Link to ViewB", destination: ViewB())
                        }
                    }
                    .navigationBarTitle("ViewA")
                }
            }) 
    }
}

struct ViewB: View {
    @State var selection = 0
    let screenOptions = ["a", "b", "c"]
    var body: some View{
        Form {
            Section {
                NavigationLink("Link to ViewC", destination: ViewC())
            }
        }
        .navigationBarTitle("ViewB")
    }
}

struct ViewC: View {
    var body: some View{
        Form {
            Section {
                Text("Test")
            }
        }
        .navigationBarTitle("ViewC")
    }
}

【问题讨论】:

  • 看起来像 sheet 中的一个错误 - 没有它也可以正常工作。您可以向 Apple 提交错误报告。
  • 终于没有遇到取模的bug (i % 2) == 0 not working :))))))))))))))))) 我笑了河流:)
  • 天哪,是的,我提交了一个错误报告。希望这会很快得到解决。
  • 我最终完全重新实现了表单。

标签: ios swift swiftui


【解决方案1】:

在工作表中使用NavigationLink 时,我也遇到了这个问题。我在 iOS 14 上的解决方案过于调侃didSelectRowAt:UITableView。选择该行时,我取消选择它。有更多代码用于检测它是否在工作表中等,但这是基本的,让它工作代码:

extension UITableView {
    
    @objc static func swizzleTableView() {
        
        guard self == UITableView.self else {
            return
        }
        
        let originalTableViewDelegateSelector = #selector(setter: self.delegate)
        let swizzledTableViewDelegateSelector = #selector(self.nsh_set(delegate:))
        
        let originalTableViewMethod = class_getInstanceMethod(self, originalTableViewDelegateSelector)
        let swizzledTableViewMethod = class_getInstanceMethod(self, swizzledTableViewDelegateSelector)
        
        method_exchangeImplementations(originalTableViewMethod!,
                                       swizzledTableViewMethod!)
    }
    
    @objc open func nsh_set(delegate: UITableViewDelegate?) {
        nsh_set(delegate: delegate)
        
        guard let delegate =  delegate else { return }
        
        let originalDidSelectSelector = #selector(delegate.tableView(_:didSelectRowAt:))
        let swizzleDidSelectSelector = #selector(self.tableView(_:didSelectRowAt:))
        
        let swizzleMethod = class_getInstanceMethod(UITableView.self, swizzleDidSelectSelector)
        let didAddMethod = class_addMethod(type(of: delegate), swizzleDidSelectSelector, method_getImplementation(swizzleMethod!), method_getTypeEncoding(swizzleMethod!))
        
        if didAddMethod {
            let didSelectOriginalMethod = class_getInstanceMethod(type(of: delegate), NSSelectorFromString("tableView:didSelectRowAt:"))
            let didSelectSwizzledMethod = class_getInstanceMethod(type(of: delegate), originalDidSelectSelector)
            if didSelectOriginalMethod != nil && didSelectSwizzledMethod != nil {
                method_exchangeImplementations(didSelectOriginalMethod!, didSelectSwizzledMethod!)
            }
        }
    }
    
    @objc open func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        self.tableView(tableView, didSelectRowAt: indexPath)

        // This is specifically to fix a bug in SwiftUI, where a NavigationLink is
        // not de-selecting itself inside a sheet.
        tableView.deselectRow(at: indexPath,
                              animated: true)
        
    }
}

(原始 swizzle 代码来自 https://stackoverflow.com/a/59262109/127853),此代码示例只是添加了 deselectRow 调用。)

别忘了给UITableView.swizzleTableView()打电话,比如application:didFinishLaunchingWithOptions:

【讨论】:

  • 这对我来说在 iPad 上崩溃了,在 iPhone 上它工作正常。你有过类似的经历吗?
  • @dehlen 我在 nsh_set 方法中添加了额外的代码来检测委托是否是 SwiftUI 类,如果是,则只替换该方法,因为我在非 swiftUI 代码上遇到问题(而且它是非 SwiftUI 代码不需要)。我正在apps.apple.com/app/appwage/id834352667#?platform=iphone 中积极使用此代码。
  • 首先感谢您回复我并与我们分享您的解决方案。在 iPhone 上,这对我有用。但是在 iPad 上运行它会导致无限循环,最终导致应用程序崩溃。由于我无法在评论中上传屏幕截图,因此这里有一个显示调试器的链接。如您所见,它在运行didSelectRow 的原始实现时崩溃。这是在任何运行 14.2 和 Xcode 12.2.0 的 iPad 上:cln.sh/ryVMcw
【解决方案2】:

将以下修饰符添加到您的 NavigationView 以设置导航视图样式并修复此问题:

.navigationViewStyle(StackNavigationViewStyle())

解释:

默认样式是 DefaultNavigationViewStyle(),来自文档:“当前正在设置样式的视图上下文中的默认导航视图样式”。

由于某种原因,这将在 iPhone 上使用 DoubleColumnNavigationViewStyle 而不是 StackNavigationViewStyle,如果您明确设置样式,它会按预期运行。

【讨论】:

  • 不是每个人都想在 iPad 上使用 iPhone 布局。
  • 提到的问题是,根据我的经验,特定于 iPhone,如果您需要在 iPadOS 上支持 StackNavigationViewStyle,您可以有条件地设置此样式。
  • 我明白了。很有趣。
猜你喜欢
  • 2021-01-04
  • 2021-04-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-30
  • 1970-01-01
  • 2013-12-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多