简体   繁体   中英

indexPathForItemAtPoint Occasionally Returning nil

In my app I have a UICollectionView which acts as a scrolling color-picker in my app. I'm having a very rare bug where once in a blue moon the color will be set to the first value in the scroller upon button press, rather than the one associated with the button the user actually touched.

I isolated this to indexPathForItemAtPoint returning nil for the button press.

For now I've hacked around the problem by simply returning when the index path returned is nil , however, I'm concerned this behavior is still not correct for a couple reasons;

  1. First of all, I looked at the touch position in the debugger and it is valid within the bounds of the collection view.
  2. Second, the trigger to get the color associated with the button occurs when the event UIControlEventTouchUpInside happens for one of the buttons in the collection. It therefore doesn't make sense to me that the code would be called for a touch not inside a button. In this case I've swapped my current bug of getting the wrong color for a bug where a button will rarely not be responsive.

I did a bit of searching and unless I missed it, all I've seen on this site are cases where the code had an implementation error and was always receiving nil, but nothing quite like this.

I was hoping someone might be able to help me identify a cause so I can fix it or at least understand why the issue is occurring.

The relevant functions are included below:

- (IBAction)myClickEvent:(id)sender event:(id)event
{
    NSSet *touches = [event allTouches];

    UITouch *touch = [touches anyObject];

    CGPoint currentTouchPosition = [touch locationInView: self.collectionViewColors];

    NSIndexPath *indexPath = [self.collectionViewColors indexPathForItemAtPoint: currentTouchPosition];

    if(!indexPath)return;

    appState.currentColor = appState.colors[indexPath.row];

    const CGFloat *components = CGColorGetComponents(appState.currentColor.CGColor);

    self.redSlider.value = components[0];
    self.greenSlider.value = components[1];
    self.blueSlider.value = components[2];

    appState.setBackgroundImagePreview(nil);
}

And the initialization function which sets the button event:

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *identifier = @"Cell";

    UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];

    UIButton *myButton = (UIButton *)[cell viewWithTag:100];

    [myButton  addTarget:self action:@selector(myClickEvent:event:) forControlEvents:UIControlEventTouchUpInside];

    /// abridged 

    [myButton setBackgroundImage:colorSquare forState:UIControlStateNormal];

    return cell;
}

Thanks!

Edit: I tried the following to get the touches, thinking that Apple might be sending multitouch / touches outside the button for some reason. No dice. It still returns a nil index path on occasion.

 NSSet *touches = [event touchesForView:sender];

indexPathForItemAtPoint: returns nil if " no item was found at the specified point " which is most commonly the case when the point falls in the spacing between cells. There are 3 flow layout properties that are commonly used to influence how cells are spaced:

  • minimumLineSpacing
  • minimumInteritemSpacing
  • sectionInset

When you get a nil index path and then ask for its row, it will always be 0 and thus appState.colors[indexPath.row] gives you the first color in your array.


One way to fix this would be to loop over all cells in indexPathsForVisibleItems and determine which one contains the center point (if any) or is closest to it. To easiest way to do that is with - layoutAttributesForItemAtIndexPath: , CGRectContainsPoint() , and some easy math.

It could also make sense for your app to simply return if you get a nil path and take no action.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM