Search code examples
iosuiscrollviewios7uicontrol

Prevent touch events on subviews of scrolling UIScrollView in iOS7


I have a UIControl inside a UIScrollView. In my UIControl's init, I rig up some touch event handlers, e.g.

[self addTarget:_delegate
         action:@selector(touchedDown) forControlEvents:UIControlEventTouchDown];

iOS6 and iOS7 behave differently when I do the following:

  1. Swipe the UIScrollView to start scrolling
  2. Tap the UIScrollView to stop scrolling

In iOS6, my app continues to behave as intended: the tap at step #2 does not call touchedDown -- the UIScrollView swallows the touch event as it immediately stops scrolling.

But in iOS7, the UIScrollView stops scrolling as expected, while touchedDown is still called.

Was there a documented API change? I'd like my app to behave identically to iOS6 in iOS7.


Solution

  • Not very elegant, but in the absence of any better ideas, here's what's working for me now:

    • On the UIScrollView, set canCancelContentTouches to YES and delaysContentTouches to NO.
    • In the UIScrollViewDelegate, toggle the UIScrollView's subview's userInteractionEnabled property when the UIScrollView scrolls:
    - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
    {
        [_contentView setUserInteractionEnabled:NO];
    }
    
    - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
    {
        if (!decelerate) {
            [_contentView setUserInteractionEnabled:YES];
        }
    }
    
    - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
    {
        [_contentView setUserInteractionEnabled:YES];
    }
    
    • Subclass the UIScrollView and implement:
    - (BOOL)touchesShouldCancelInContentView:(UIView *)view
    {
        return YES;
    }
    
    • Subclass the UIControl and implement touchesCancelled:withEvent to reverse whatever the UIControlEventTouchDown handler does:
    - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
    {
        //custom logic
    }