Grinarn
Grinarn

Reputation: 127

UIScrollView inside a UITableViewCell - No didSelect call

I have a tableviewCell, where the user can scroll horizontally. Since the scrollView covers nearly the whole cell, the tableView method didSelectRow gets not called if the user clicks the cell.

So I thought, I could pass the touch event of the UIScrollView to the cell, but still the didSelectRow doesnt gets called. I subclassed UIScrollView to pass the touch event only, if the touch was not a drag:

- (void) touchesEnded: (NSSet *) touches withEvent: (UIEvent *) event
{
    NSLog(@"touch scroll");
    // If not dragging, send event to next responder
    if (!self.dragging)
        [self.superview touchesEnded: touches withEvent:event];
    else
        [super touchesEnded: touches withEvent: event];
}

Any ideas on how to pass the click to the table, to get the delegate-methods called and keep the scrolling inside the scrollview?

Upvotes: 5

Views: 4227

Answers (5)

budiDino
budiDino

Reputation: 13527

Swift 3

scrollView.isUserInteractionEnabled = false
contentView.addGestureRecognizer(scrollView.panGestureRecognizer)

Upvotes: 0

cph2117
cph2117

Reputation: 2681

You can actually do this without subclassing UIScrollView. Whether you have a custom cell, or are setting properties in cellForRowAtIndexPath in the UITableView, you can do the following:

[cell.contentView addSubview:yourScrollView];
yourScrollView.userInteractionEnabled = NO;
[cell.contentView addGestureRecognizer:yourScrollView.panGestureRecognizer];

The reason you can do this is because scrollView has its own panGestureRecognizer that's accessible to the programmer. So, just adding it to the cell's view will trigger the scrollview's gesture delegates.

The only drawback of this approach is that subviews of the scroll view are unable to receive any touch input. If you need this you will have to chose a different approach.

Upvotes: 22

cnotethegr8
cnotethegr8

Reputation: 7510

The selected answer is correct, but I updated the code based on a bug I was getting.

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
    if (self.dragging) {
        [super touchesMoved:touches withEvent:event];
    } else {
        if ([self.delegate isKindOfClass:[UITableViewCell class]]) {
            [(UITableViewCell *)self.delegate touchesCancelled:touches withEvent:event];
        }

        [self.superview touchesMoved:touches withEvent:event];
    }
}

If your self.delegate is not the UITableViewCell, than replace that property with a property to your cell.

The cell needs to retrieve the cancel touch event during movement to prevent the undesired results. It can be easily reproducible as follows.

  • Highlight the cell (assuming the scroll view is over the whole cell, if not highlight the scroll view)
  • While the cell is highlighted, drag the table view
  • Select any other cell and now the previously highlighted cell will retrieve the didSelectCell state

Another point to mention is that order matters! If the self.delegate is not called before the self.superview then the highlighted state wont happen.

Upvotes: 1

gils
gils

Reputation: 61

I just encountered the same problem.
In your subclass make sure to include the full set of methods:

-(void) touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
    if (!self.dragging)
        [self.superview touchesCancelled: touches withEvent:event];
    else
        [super touchesCancelled: touches withEvent: event];
}

-(void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
    if (!self.dragging)
        [self.superview touchesMoved: touches withEvent:event];
    else
        [super touchesMoved: touches withEvent: event];
}

-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    if (!self.dragging)
        [self.superview touchesBegan: touches withEvent:event];
    else
        [super touchesBegan: touches withEvent: event];
}

-(void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
    if (!self.dragging)
        [self.superview touchesEnded: touches withEvent:event];
    else
        [super touchesEnded: touches withEvent: event];
}

Upvotes: 6

Bryan Chen
Bryan Chen

Reputation: 46578

try set this

_scrollView.canCancelContentTouches = NO

also, it is bad to partially forward touch events

Upvotes: -1

Related Questions