带有onTapGesture的分段式选择器无法响应点击

时间:2019-07-30 12:46:57

标签: swiftui segmentedcontrol

我尝试重新实现我使用的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()相同。

3 个答案:

答案 0 :(得分: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)")
    }
}

注意:根据我的经验,在以前的Beta中向SegmentedControl添加tapGesture会导致SegmentedControl无响应,所以我不确定为什么它能正常工作为您提供以前的版本。从SwiftUI beta 5开始,我认为尚无办法为手势分配优先级。

编辑:您可以使用.highPriorityGesture()使手势优先于视图中定义的手势,但是优先级较高的手势会引起问题。但是,您可以使用.simultaneousGesture(),我认为这可以解决您的问题,但是我认为它在SwiftUI Beta 5中并不能完全正常工作。

答案 1 :(得分:0)

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

答案 2 :(得分:0)

我能够在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
                }
            }