Reputation: 1074
How do I determine if a DatePicker is currently spinning/rolling? I have tried just about everything and looked at all the answers on here but none are right or worked.
Essentially, I would like to disable a button while it is spinning then enable the same button when it stopped.
Thanks!
Upvotes: 1
Views: 461
Reputation: 41642
I wanted to do the same thing, and so poked around UIControl and the class dump for UIDatePicker. Nothing seemed to work, as maddy
stated in the comment section.
Well, it did occur to me that this is some way to do it - screen shot the picker view over a short time - say 50 ms - and do an image compare between the before and after to see if its changing. That sure seems like a lot of work!
So I experimented with various approaches (iOS13), and I found that I could use a gesture recognizer to detect when the picker was first touched, as well as when the UIDatePicker's own recognizer was updating. This let me generally detect when user interaction likely ended.
Then, I could await the action method signally that the spinning stopped. Ah, but what happens if the user just moved one of the wheels, then put it back? If the new date is the same as the old one, no action method. So what I did was use a delayed dispatch work item, and after two seconds ruled the spinner as stopped.
final class DHDatePicker: UIDatePicker, UIGestureRecognizerDelegate {
var isSpinning = false { didSet { print("IS SPINNING", isSpinning) } }
private var didAddGR = false
private var cancelBlock = DispatchWorkItem(block: {})
override init(frame: CGRect) {
super.init(frame: frame)
let gr = UISwipeGestureRecognizer()
gr.direction = [.up, .down]
gr.delegate = self
self.addGestureRecognizer(gr)
self.addTarget(self, action: #selector(dateChanged(_:)), for: .primaryActionTriggered)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
@objc func gr(_ gr: UISwipeGestureRecognizer) {
switch gr.state {
case .ended, .cancelled, .failed:
cancelBlock.cancel()
cancelBlock = DispatchWorkItem(block: {
if self.isSpinning {
self.isSpinning = false
}
})
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0, execute: cancelBlock)
print("GR ENDED")
default:
print("WTF")
break
}
}
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
isSpinning = true
return true
}
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
if didAddGR == false {
didAddGR = true
print("DP Attach to Other GR")
otherGestureRecognizer.addTarget(self, action: #selector(gr(_:)))
}
return false
}
@objc func dateChanged(_ sender: UIDatePicker) {
print("DP ActionMethod")
cancelBlock.cancel()
isSpinning = false
}
}
Upvotes: 1