سؤال

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.

هل كانت مفيدة؟

المحلول 3

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
}

نصائح أخرى

workaround for iOS 7

@interface UIScrollViewFixed : UIScrollView

@end

@implementation UIScrollViewFixed

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
    if (self.isDragging || self.isDecelerating) {
        return self;
    }
    return [super hitTest:point withEvent:event];
}

@end

Just replace the event type

UIControlEventTouchDown must be UIControlEventTouchUpInside

Same here with UIButtons on a UIScrollView. This is my solution for now.

Instead of using the contents UIControlEventTouchDown event:

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

I implemented the UIResponder touchesEnded method in my content UIViewController:

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
// my scroll content touch logic
}

If the user touches the content and starts dragging the touchesEnded handler will not be called. The UIResponder touchesCanceled method will.

If the user does not drag the UIscrollview the touchesEnded handler is fired, which can be used for touch logic.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top