24

I have UIScrollView loaded with UIButtons and on UIButton action I have highlighted UIImage of each UIButton.

If I don't set delaysContentTouches as NO then highlighted UIImage of UIButton will not shown if I touch up UIButton very fast. After I set delaysContentTouches property as NO then only UIButton highlighted UIImage is shown.

Now after setting delaysContentTouches property as NO for UIScrollView. I can not scroll my UIScrollView by dragging on the UIButtons. Now how can I resolve this issue.

Please give me an advise.

Thanks in advance.

Juan Boero
  • 6,281
  • 1
  • 44
  • 62
Piyush Hirpara
  • 1,279
  • 1
  • 11
  • 29
  • 3
    The delaysContentTouches means that the scroll view will always get the touch first and decide whether to scroll or not depending on if you slide. This first test is the delay that you see, when you set this property to NO you are saying that you do not want the scroll view to take the touch first but all it's subviews should accept the touch.... – A'sa Dickens Jul 17 '13 at 13:51
  • If the button is really small, then not scrolling where that button is could work. If you have a really big button but still want the button to take the touch first but still scroll when you slide your finger, then the only way i can think of doing that would be to add a gesture recognizer for a slide err swipe. Gesture recognizers override touch events and when you call the method of the gesture just re set you scrollview's content off set. I have not tried this so i don't know if it will work.... – A'sa Dickens Jul 17 '13 at 13:54
  • Can I do something like when I long touch my button then my touch is passed to the below scrollview. Is it possible? or how can i achieve this? – Piyush Hirpara Jul 18 '13 at 06:28

6 Answers6

44

Here's what works for me. Subclass UIScrollView, and implement only this method:

- (BOOL)touchesShouldCancelInContentView:(UIView *)view {
    return YES;
}

Then set delaysContentTouches = NO;

Voila! Works just like the home screen: Highlights buttons immediately, but still allows scrolling :)

Chris
  • 39,719
  • 45
  • 189
  • 235
  • this worked for me. other solutions below didn't (in combination with tableView.delaysContentTouches = YES) – Joris Weimar Sep 30 '14 at 21:25
  • This is an old post but I found it helpful today. In addition, I had an issue with the delaysContentTouches not working near the bottom of the screen. It turned out to be a window gesture recognizer. Hope this helps others in the future. Read more here: https://stackoverflow.com/questions/19799961/uisystemgategesturerecognizer-and-delayed-taps-near-bottom-of-screen – Addison Aug 10 '18 at 04:41
11

I found that in iOS 8, the UIScrollView's underlying UIPanGestureRecognizer is not respecting the UIScrollView's delaysContentTouches property. I consider this an iOS 8 bug. Here's my workaround:

theScrollView.panGestureRecognizer.delaysTouchesBegan = theScrollView.delaysContentTouches
lifjoy
  • 2,158
  • 21
  • 19
  • I believe you meant theScrollView.panGestureRecognizer.delaysTouchesBegan = theScrollView.delaysContentTouches; It helped me, thanks for this! I hope it break something else. – Lope Sep 23 '14 at 21:22
  • Thanks. You are correct. I meant that the PanGestureRecognizer's delaysTouchesBegan property should mirror the UIScrollView's delaysContentTouches property. – lifjoy Sep 24 '14 at 22:32
  • FYI; I submitted a Radar bug report to Apple, which they have marked as a duplicate. – lifjoy Sep 26 '14 at 19:15
  • Here what is the value for theScrollView.delaysContentTouches? YES or NO – Kirti Nikam Jun 28 '18 at 09:38
  • I think I used YES for theScrollView.delaysContentTouches. But the point is that theScrollView.panGestureRecognizer.delaysTouchesBegan should mirror the value of theScrollView.delaysContentTouches. – lifjoy Jul 10 '18 at 19:46
8

OK I have resolved by implementing below method :

- (BOOL)touchesShouldCancelInContentView:(UIView *)view
{
    NSLog(@"touchesShouldCancelInContentView");

    if ([view isKindOfClass:[UIButton class]])
        return NO;
    else
        return YES;
}
Piyush Hirpara
  • 1,279
  • 1
  • 11
  • 29
  • Doesn't work for me unfortunately (i did set the scrollviews delegate) – Chris Jan 15 '14 at 22:18
  • Ok it works if you subclass uiscrollview (this isn't a delegate method), and invert the NO/YES values above. – Chris Jan 15 '14 at 22:23
  • First of all this should return `YES` if the view is a `UIButton`. `NO` is already the default behavior. Secondly, it should return `[super touchesShouldCancelInContentView:view]` in the else clause. – devios1 Jun 05 '15 at 22:28
4

Unable to find a satisfactory solution online so far (and it seems to be that Apple is ignoring the issue). Found a thread on Apple's developer forum with some suggestions in there that may help: UIScrollView: 'delaysContentTouches' ignored

I was able to use the workaround from this link. To summarize the workaround (I'm para-quoting here):

UIEvent objects contain a time stamp.

You can record the time stamp at the time of touchesBegan on your embedded subview.

In touchesMoved of scrollView's subview, look at the time stamp and location again.

If the touch has not moved very far and more than, say, 0.1 seconds have passed, you can assume the user touched the subview and then delayed movement.

In this case, the UIScrollView will have decided, independently, that this is NOT a scrolling action even though it will never tell you that.

So, you can have a local state variable to flag that this condition of delayed movement occurred and process events received by the subview.

Here's my code:

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
    // store the timestamp
    _beginDragTimeStamp = event.timestamp;    

    // your embedded subview's touches begin code
}

-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
   // compare and ignore drag if time passed between tap and drag is less than 0.5s
   if(event.timestamp - _beginDragTimeStamp < 0.5) return;

   // your drag code
}
Kirill E.
  • 338
  • 2
  • 9
2

I had same issue & same hierarchy of the views, With latest sdk , just use it :

Setting delaysContentTouches to NO for UIButton in the same UITableViewCell.

self.scrollview.delaysContentTouches = NO
Ash
  • 5,525
  • 1
  • 40
  • 34
1
  1. Create a subclass of the UIScrollView (or UITableView, or UICollectionView, or any other UIScrollView subclass that you use).

  2. Implement the below method:

    - (BOOL)touchesShouldCancelInContentView:(UIView *)view {
    
         if ([view isKindOfClass:UIButton.class]) {
    
              return YES;
         }
    
         return [super touchesShouldCancelInContentView:view];
    }
    
  3. Set this subclass at xib/storyboard as a "Custom Class" class if you use the interface builder.

  4. Unselect Delay Touch Down in a xib or set delaysContentTouches = NO in code.

Filinovi4
  • 23
  • 4