【问题标题】:Segmented Picker with onTapGesture doesn't respond to taps带有 onTapGesture 的分段选取器不响应点击
【发布时间】:2019-07-30 12:46:57
【问题描述】:

我尝试重新实现我正在使用的 SegmentedControlers,因为它们在 Xcode 11 beta 5 中已被弃用。这花了一段时间,但我得到了我想要的外观。但是,当我用 onTapGesture() 替换 tapAction 时,选择器停止工作。

下面的代码显示了问题。注释掉 pickerStyle 会得到一个与 onTapGesture() 一起工作的轮子选择器

import SwiftUI

var oneSelected = false
struct ContentView: View {
    @State var sel = 0
    var body: some View {
        VStack {
            Picker("Test", selection: $sel) {
                Text("A").tag(0)
                Text("B").tag(1)
                Text("C").tag(2)
            }
            .pickerStyle(SegmentedPickerStyle())
            Picker("Test", selection: $sel) {
                Text("A").tag(0)
                Text("B").tag(1)
                Text("C").tag(2)
            }
            .pickerStyle(SegmentedPickerStyle())
            .onTapGesture(perform: {
                oneSelected = (self.sel == 1)
            })
            Text("Selected: \(sel)")
        }
    }
}

#if DEBUG
struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
#endif

我希望 Picker().pickerStyle(SegmentedPickerStyle()) 应该像 SegmentedController() 一样工作。

【问题讨论】:

    标签: swiftui segmentedcontrol


    【解决方案1】:

    您添加的tapGesture 干扰了选择器的内置点击手势识别,这就是为什么您的.onTapGesture 中的代码在选择器被点击时运行,但选择器本身没有响应点击。在您的情况下,我建议采用不同的方法:将符合ObservableObject 的视图模型传递给您的ContentView,并让它包含一个@Published 变量以供选择器选择。然后向该变量添加一个属性观察器,检查所选选项是否为 1。

    例如:

    class ViewModel: ObservableObject {
        @Published var sel = 0 {
            didSet {
                oneSelected = oldValue == 1
            }
        }
        var oneSelected = false
    }
    

    SceneDelegate.swift,或声明ContentView 的任何地方:

    ContentView().environmentObject(ViewModel())
    

    ContentView.swift:

    @EnvironmentObject var env: ViewModel
    var body: some View {
        VStack {
            Picker("Test", selection: $env.sel) {
                Text("A").tag(0)
                Text("B").tag(1)
                Text("C").tag(2)
            }
            .pickerStyle(SegmentedPickerStyle())
            Picker("Test", selection: $env.sel) {
                Text("A").tag(0)
                Text("B").tag(1)
                Text("C").tag(2)
            }
            .pickerStyle(SegmentedPickerStyle())
            Text("Selected: \(sel)")
        }
    }
    

    注意:根据我的经验,在以前的测试版中向 SegmentedControl 添加一个 tapGesture 会导致 SegmentedControl 没有响应,所以我不确定为什么它在以前的测试中对你有用版本。从 SwiftUI beta 5 开始,我认为没有办法为手势分配优先级。

    编辑:您可以使用.highPriorityGesture() 使您的手势优先于视图中定义的手势,但您的手势具有更高的优先级会导致您的问题。但是,您可以使用 .simultaneousGesture(),我认为这可以解决您的问题,但我认为它在 SwiftUI Beta 5 中还没有完全发挥作用。

    【讨论】:

    • 我正计划做一些类似但更简单的事情。如果我删除了 pickerStyle(),我的代码中的第二个选择器就可以工作,所以它是分段代码中的某些东西不起作用。
    • 可能是分段控件的代码具有不同的手势相关代码,因为视图需要知道用户在视图中点击的位置,而在默认选择器中点击的位置在视图不需要知道。我们没有 SwiftUI 的源代码,因此无法确切知道为什么分段控件选择器样式的点击手势识别的点击手势的优先级低于手动附加的点击手势,但默认情况并非如此选择器。
    • 为了进一步说明这是一个与手势优先级相关的问题,如果您将 tapGesture 添加到默认选择器,选择器会正确响应您的触摸,但您手动添加的 tapGesture 未注册.在这种情况下,选择器的手势识别优先于您手动添加的手势识别。如果无法访问 SwiftUI 源代码,我无法明确告诉您为什么会这样。
    • 感谢您的宝贵时间。我的解决方案是为 Int 创建一个包装器 ObservableObject 类,当它改变值时调用一个闭包。现在我不用担心水龙头了。
    • @MichaelSalmon 是的,没问题,这是我的回答建议您采取的路线。如果它是有帮助的和彻底的,你能接受答案吗?
    【解决方案2】:
    class IndexManager: ObservableObject {
        @Published var index = 0 {
            didSet {
                publisher.send(index)
            }
        }
        let publisher = PassthroughSubject<Int, Never>()
    }
    
    struct SegmentedPickerView: View {
    
        private let strings = ["a", "b", "c"]
        @ObservedObject private var indexManager = IndexManager()
    
        var body: some View {
            Picker("", selection: $indexManager.index) {
                ForEach(strings, id: \.self) {
                    Text($0).tag(self.strings.firstIndex(of: $0)!)
                }
            }.pickerStyle(SegmentedPickerStyle())
                .onReceive(indexManager.publisher) { int in
                    print("onReceive \(int)")
            }
        }
    }
    

    【讨论】:

    • 我的绝对答案。
    【解决方案3】:

    我能够在 onTapGesture 中使用以下条件实现此功能

    @State private var profileSegmentIndex = 0    
    
    Picker(selection: self.$profileSegmentIndex, label: Text("Music")) {
                        Text("My Posts").tag(0)
                    
                    Text("Favorites").tag(1)
                }
                .onTapGesture {
                    if self.profileSegmentIndex == 0 {
                        self.profileSegmentIndex = 1
                    } else {
                        self.profileSegmentIndex = 0
                    }
                }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多