Event Handling Guide for iOS said "There may be times when you want a view to receive a touch before a gesture recognizer. ", but I couldn't find how to do that.
I tried delaysTouchesEnded = false, but it does not have any effect.
@IBOutlet weak var myPickerView: UIPickerView!
override func viewDidLoad() {
super.viewDidLoad()
let tapGesture:UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(MyViewController.pickerViewTapped(_:)))
tapGesture.delegate = self
tapGesture.delaysTouchesEnded = false
myPickerView.addGestureRecognizer(tapGesture)
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int){
// called by UIPickerView
print("pickerView called!")
}
func pickerViewTapped(_ sender: UITapGestureRecognizer) {
// called by UITapGestureRecognizer
print("pickerViewTapped called!")
}
When I tap myPickerView, the console would be
pickerViewTapped called!
pickerView called!
But I want them in reverse order. How to do that?
Short answer:
You can't do it using UIGestureRecognizer only.
Long answer:
There is always a delay between the action of select a row of a UIPickerView and the call of the method didSelectRow
, due to the animation required for move the row to the center of UIPickerView itself.
Also note that if you tap of the row at center, you don't call the didSelectRow
method, but pickerViewTapped
only.
This delay necessarily make this sequence of the execution:
pickerViewTapped
pickerView(_ pickerView: UIPickerView,
didSelectRow row: Int, inComponent component: Int){
The solution I found is this:
func pickerViewTapped(_ sender: UITapGestureRecognizer) {
// called by UITapGestureRecognizer
let timeDelay = 0.6
//0.6 is arbitrary value, depends on you
DispatchQueue.main.asyncAfter(deadline: .now() + timeDelay) {
print("pickerViewTapped called!")
}
}
I know maybe it is not the answer you were looking for, neither I know why you would have such behaviour but this is the nearest solution I've found.