Сегментированный выбор с onTapGesture не реагирует на нажатия

Я попытался заново реализовать SegmentedControlers, которые я использовал, поскольку они устарели в Xcode 11 beta 5. Это заняло некоторое время, но я получил желаемый вид. Однако, когда я заменил tapAction на onTapGesture (), сборщик перестал работать.

Код ниже показывает проблему. Комментируя 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 ().


person Michael Salmon    schedule 30.07.2019    source источник


Ответы (3)


Добавленный вами 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())

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

Примечание. По моему опыту, добавление TapGesture к SegmentedControl в предыдущих бета-версиях привело к тому, что SegmentedControl не отвечает, поэтому я не уверен, почему он работал у вас в предыдущей версии. Что касается SwiftUI beta 5, я не думаю, что есть способ назначать уровни приоритета жестам.

Изменить: вы можете использовать .highPriorityGesture(), чтобы ваш жест имел приоритет над жестами, определенными в представлении, но ваш жест, имеющий более высокий приоритет, вызывает вашу проблему. Однако вы можете использовать .simultaneousGesture(), который, как я думал, будет решением вашей проблемы, но я не думаю, что он полностью функционален в SwiftUI Beta 5.

person RPatel99    schedule 30.07.2019
comment
Я планировал сделать что-то подобное, но попроще. Второй сборщик в моем коде работает, если я убираю pickerStyle (), поэтому в сегментированном коде что-то не работает. - person Michael Salmon; 30.07.2019
comment
Может случиться так, что код для сегментированного элемента управления имеет другой код, связанный с жестами, потому что представление должно знать, где в представлении коснулся пользователь, в то время как в средстве выбора по умолчанию расположение касания в представлении не нужно знать . У нас нет исходного кода для SwiftUI, поэтому невозможно точно узнать, почему жест касания для распознавания жеста касания в стиле сегментированного средства выбора имеет более низкий приоритет, чем добавленный вручную жест касания, но это не относится к случаю по умолчанию сборщик. - person RPatel99; 30.07.2019
comment
И чтобы дополнительно проиллюстрировать, что это проблема, связанная с приоритетом жестов, если вы добавляете TapGesture в средство выбора по умолчанию, средство выбора правильно реагирует на ваше прикосновение, но жест касания, который вы добавили вручную, не регистрируется. В этом случае распознавание жеста средства выбора имеет приоритет над тем, которое вы добавили вручную. Без доступа к исходному коду SwiftUI я не могу однозначно сказать вам, почему это так. - person RPatel99; 30.07.2019
comment
Спасибо за ваше время. Мое решение заключалось в создании класса-оболочки ObservableObject для Int, который вызывает закрытие при изменении значения. Теперь мне не нужно беспокоиться о кранах. - person Michael Salmon; 31.07.2019
comment
@MichaelSalmon Да, нет проблем, это тот путь, который я предложил вам выбрать. Если бы он был полезным и подробным, не могли бы вы принять ответ? - person RPatel99; 31.07.2019

мне удалось заставить это работать со следующим условием в 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
                }
            }
person Di Nerd    schedule 03.11.2020

person    schedule
comment
Абсолютный ответ для меня. - person Rajan Twanabashu; 13.07.2021