I use UIScrollView to make large-sized (larger than 320px) UI on iPhone.
I made an instance of UIScrollView and added some subviews on it. The problem is that I want
UIScrollView has a scrollEnabled property that allows you to disable scrolling programatically. It also has a delegate (UIScrollViewDelegate) that allows you to see events such as scrolling starting/ending. Seems that you should be able to cook something up with those options combined in some way.
The simplest way to do this is set delayContentTouches
to NO
for the scrollview. That way the default behaviour is set so that anything which is a UIControl will pass the touches on to the control immediately andeverything else will scroll.
If you want to detect touches inside any of the subviews of the UIScrollView, you will have to subclass UIScrollView and override the touchesShouldBegin
and touchesShouldCancelInContentView
methods which are specifically created for this purpose.
Other than this, there is no way you can identify touches in the subviews as UIScrollView tends to handle all touches itself and doesn't pass them to its subviews.
All the best.
You can also sublcass UIScrollViewController and override the touchesBegan, touchesMoved and touchesEnded methods. If your implementation never calls the superclass implementation, then it won't scroll.
The property you're really interested in -- and I'm actually testing this out right now, because I have the same problem you do -- is canCancelContentTouches
.
If the value of this property is NO, the scroll view does not scroll regardless of finger movement once the content view starts tracking.
If this doesn't give you the results you want, subclass UIScrollView and override the touchesShouldBegin:withEvent:inContentView
method, which is what the accepted answer suggests.
My problem was having a view that a user could draw in but the scroll view was hijacking the touch and scrolling instead of drawing. This is my working solution:
In my drawing view I have:
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
// Disable scroll on touch begin
setContainerScrollingEnabled(false)
super.touchesBegan(touches, with: event)
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
// Reenable scroll on touch end
setContainerScrollingEnabled(true)
super.touchesEnded(touches, with: event)
}
private func setContainerScrollingEnabled(_ enabled: Bool) {
// loop up superviews to find the scrollview
func scrollingSuperview(of view: UIView) -> UIScrollView? {
guard let superview = view.superview else { return nil }
if let scrolling = view.superview as? UIScrollView { return scrolling }
return scrollingSuperview(of: superview)
}
// and switch on/off scrolling
let scrollView = scrollingSuperview(of: self)
scrollView?.isScrollEnabled = enabled
}
and in the view controller containing the scroll view I have:
// Not sure what exactly this does, but I think it allows the drawing view to have precedence. This was the missing piece of the puzzle.
scrollView.delaysContentTouches = false