DenVog
DenVog

Reputation: 4286

Button on CollectionView Cell Only Receives Taps After Long Press

I am programmatically adding a UIButton to a custom UICollectionViewCell. Taps on the button are only detected if I do a long press on the cell first. Then the button works as expected. I have to do the same long press on each cell individually in order to get their respective button to recognize taps.

Note that single taps (i.e. didSelectItemAtIndexPath) on cells work as expected. So does long press on a cell. It might be worth noting that UILongPressGestureRecognizer is the only gesture added to the collectionView.

UICollectionViewCell class

- (UIButton *)stackInfoButton
{
    if(_stackInfoButton == nil)
    {
        self.stackInfoButton = [UIButton buttonWithType:UIButtonTypeInfoDark];
        [self.stackInfoButton setShowsTouchWhenHighlighted:YES];
    }
    return _stackInfoButton;
}

- (void)layoutSubviews
{
  // Other stuff here. Removed for readability
    self.stackInfoFrame = CGRectMake(4.0f, self.bounds.size.height - self.stackInfoButton.bounds.size.height - 4, self.stackInfoButton.bounds.size.width, self.stackInfoButton.bounds.size.height);
}

- (void)drawRect:(CGRect)rect
{
  // Other stuff here. Removed for readability
  self.stackInfoButton.frame = self.stackInfoFrame;
  [[self contentView] addSubview:self.stackInfoButton];
}

UICollectionViewController class

- (void)viewDidLoad
{
  [super viewDidLoad];
  // Other stuff here. removed for readability

  self.longPressGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPress:)];
  self.longPressGesture.delegate = self;
  [self.collectionView addGestureRecognizer:self.longPressGesture];
  self.longPressGesture.cancelsTouchesInView = NO;
}

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
  DVCardViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:kDVCollectionViewCellReuseIdentifier forIndexPath:indexPath];
  cell.indexPath = indexPath;
  // Other stuff here. Removed for readability
  [cell.stackInfoButton addTarget:self action:@selector(stackInfoButtonTapped:) forControlEvents:UIControlEventTouchUpInside];     
  return cell;
}

- (void)stackInfoButtonTapped:(id)sender
 {
   NSLog(@">>> Entering %s <<<", __PRETTY_FUNCTION__);
 }

-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
    NSLog (@"Touch View : %@", touch.view);
// tried both.
//    DVCardViewCell *cell;
//    if (touch.view == cell.stackInfoButton)
        if ( [touch.view isKindOfClass:[UIButton class]] )
{
    NSLog(@"Gesture on button, returns no");
    return NO;
}
NSLog(@"Gesture returns outside, yes");
return YES;
}

Suggestions appreciated. I've been through many UICollectionView threads on SO. Yet to find one that addresses my issue. Thanks.

Upvotes: 0

Views: 1098

Answers (2)

Duc
Duc

Reputation: 650

Try this

self.LongPressGesture.cancelsTouchesInView = NO;

Sorry was mistaken. never mind.

This looks really weird:

- (UIButton *)stackInfoButton
{
   if(_stackInfoButton == nil)
   {
      self.stackInfoButton = [UIButton buttonWithType:UIButtonTypeInfoDark]; // theoretically your app should crash now
      [self.stackInfoButton setShowsTouchWhenHighlighted:YES];
   }
   return _stackInfoButton;
 }

Look at self.stackInfoButton = [UIButton buttonWithType:UIButtonTypeInfoDark];

It must be

 _stackInfoButton = [UIButton buttonWithType:UIButtonTypeInfoDark];
 [_stackInfoButton setShowsTouchWhenHighlighted:YES];

maybe it helps.

Upvotes: 0

Wain
Wain

Reputation: 119031

You say you have added a gesture to the collection view, so you need to teach that gesture not to steal touches that it shouldn't get involved with. Add your controller as the delegate of the gesture and implement gestureRecognizer:shouldReceiveTouch:. In that method check the view that the touch hit and, if it's a button, return NO to prevent the gesture from getting involved.

Upvotes: 0

Related Questions