简体   繁体   English

如果包装在 NavigationView (macOS) 中,则 SwiftUI 列表选择绑定在每次单击时更新两次

[英]SwiftUI List selection binding updates twice on every click, if wrapped in NavigationView (macOS)

Given the below code, I made a strange observation (on macOS).鉴于下面的代码,我做了一个奇怪的观察(在 macOS 上)。 If a List is wrapped in a NavigationView I suddenly get two updates per click on a row (one on mouseDown - aka holding the mouse click down and not releasing it, one on mouseUp - aka releasing the mouse click).如果 List 包含在 NavigationView 中,我突然每次点击一行都会获得两个更新(一个在 mouseDown 上 - 也就是按住鼠标点击而不释放它,一个在 mouseUp - 也就是释放鼠标点击)。 This doesn't happen on a plain simple list, or if it's wrapped in an HStack instead.这不会发生在简单的列表上,或者如果它被包装在 HStack 中。 Does anyone know why and how I can control / change this behavior?有谁知道我为什么以及如何控制/改变这种行为?

See HStack version in action:查看 HStack 版本:

基于 HStack

See NavigationView version in action:查看 NavigationView 版本:

基于导航视图

struct ContentView: View {
    @State var selection: Set<Int> = []

    var body: some View {
        List(0..<20, selection: Binding(get: {
            self.selection
        }, set: { val in
            print("set \(val)")
            self.selection = val
        })) { idx in
            Text("\(idx)")
        }

        Color.red
        Color.green
        Color.blue
    }
}

// Wrapped in a HStack, 1 update per row selection is triggered, as expected!
struct HStackVersion: View {
    var body: some View {
        HStack(spacing:0.0) {
            ContentView()
        }
    }
}

// Wrapped in a NavigationView, 2 updates per row selection are triggered??
struct NavigationViewVersion: View {
    var body: some View {
        NavigationView {
            ContentView()
        }
    }
}

The screenshot below shows the stacktrace for a breakpoint in the setter showing that SwiftUI.ListCoreCoordinator is setting the binding twice.下面的屏幕截图显示了设置器中断点的堆栈跟踪,显示SwiftUI.ListCoreCoordinator设置了两次绑定。 I've seen a similar problem with Map here .我在这里看到了与Map类似的问题。 I'm not sure if duplicate calls to binding setters is part of their design or not but it understandably could be, given that SwiftUI coalesces all state changes into a single call to body .我不确定对绑定设置器的重复调用是否是他们设计的一部分,但它可以理解,因为 SwiftUI 将所有状态更改合并到对body的单个调用中。

If you'd like to work around the issue then I would suggest going with the more standard onChange modifier instead of that custom Binding , onChange is only called once for the new value, eg如果您想解决这个问题,那么我建议您使用更标准的onChange修饰符而不是那个自定义BindingonChange只为新值调用一次,例如

struct MacListProbView: View {
    @State var selection: Set<Int> = []

    var body: some View {        
        List(0..<20, selection: $selection) { idx in
            Text("\(idx)")
        }
        .onChange(of: selection) { newSelection in
            print("set \(newSelection)")
        }
    }
}

struct MacListProbViewNav: View {
    var body: some View {
        NavigationView {
            MacListProbView()
            Color.red // note it's more efficient to have these here because they are not affected by the selection value.
            Color.green
            Color.blue
        }
    }
}

xcode 堆栈跟踪和断点

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM