4

When I embed a custom UIControl inside a ViewController that's presented modally with the new iOS13 automatic style, touchesCancelled is called whenever a pan gesture moves more than a few points.

The native UIKit UISlider doesn't do this. You can pan a UISlider within an automatic style modal ViewController without issue.

UIScrollView has touchesShouldCancel(in view: UIView) where you can force it to allow touches in specified views but I can't find anything in the docs for this new style of modal presentation.

thattyson
  • 718
  • 8
  • 17

3 Answers3

6

You can implement gestureRecognizerShouldBegin of UIGestureRecognizerDelegate on your UIControl and return false if it is of UIPanGestureRecognizer

//MARK: UIGestureRecognizerDelegate
extension RangeSlider: UIGestureRecognizerDelegate {
    public override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
        return !(gestureRecognizer is UIPanGestureRecognizer)
    }
}
Marlo Quidato
  • 573
  • 5
  • 7
2

If you use the range slider inside an UITableViewCell, this will catch the events from UIGestureRecognizerDelegate. Although strange that gestureRecognizerShouldBegin is not triggered here either. Is not optimal but maybe someone else has a new idea after noticing this.

extension RangeTableViewCell {
override func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRequireFailureOf otherGestureRecognizer: UIGestureRecognizer) -> Bool {
    // Very hackish but there is no other option I've found for now
    // Consider using a custom modal presentation style and transition
    // this gesture actually makes the range slider call cancelTracking so we disable it
    if otherGestureRecognizer is UIPanGestureRecognizer && otherGestureRecognizer.view?.className.contains("UIDropShadowView") ?? false {
        otherGestureRecognizer.isEnabled = false
    }
    return false
}

}

PS: I tried using the above func as return otherGestureRecognizer is UIPanGestureRecognizer; did not work either

Reza Jenabi
  • 3,884
  • 1
  • 29
  • 34
Cata David
  • 21
  • 2
0

The issue seems to be in using overrides of the UIControl functions touchesBegan, touchesMoved, touchesEnded, and touchesCancelled to observe drags. These touch events can't be intercepted like is possible with UIGestureRecognizerDelegate so there's no way to stop the modal drag from forcing touchesCancelled.

The answer seems to be: don't use UIControl touch event methods. Rather, - like other answers indicate works - use a UIPanGestureRecognizer and the delegate method gestureRecognizerShouldBegin.

The trouble all along was trying to use a UIControl as Apple documents say you should.

thattyson
  • 718
  • 8
  • 17