indexPathForItemAtPoint 偶尔返回 nil

Posted

技术标签:

【中文标题】indexPathForItemAtPoint 偶尔返回 nil【英文标题】:indexPathForItemAtPoint Occasionally Returning nil 【发布时间】:2015-03-29 18:36:43 【问题描述】:

在我的应用程序中,我有一个 UICollectionView,它在我的应用程序中充当滚动颜色选择器。我遇到了一个非常罕见的错误,其中一旦在蓝色月亮中,颜色将在按钮按下时设置为滚动条中的第一个值,而不是与用户实际触摸的按钮相关联的值。

我将此隔离到indexPathForItemAtPoint 返回nil 以按下按钮。

现在我已经通过在返回的索引路径是nil 时简单地返回来解决这个问题,但是,我担心这种行为仍然不正确,有几个原因;

    首先,我在调试器中查看了触摸位置,在集合视图的范围内是有效的。 其次,当集合中的某个按钮发生UIControlEventTouchUpInside 事件时,触发获取与按钮关联的颜色。因此,对我来说,代码将被调用以进行触摸而不是在按钮内是没有意义的。在这种情况下,我将当前获取错误颜色的错误替换为按钮很少没有响应的错误。

我做了一些搜索,除非我错过了,否则我在这个网站上看到的只是代码有实现错误并且总是收到 nil 的情况,但没有像这样的情况.

我希望有人能够帮助我确定原因,以便我可以解决它或至少了解问题发生的原因。

相关功能如下:

- (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);

以及设置按钮事件的初始化函数:

- (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;

谢谢!

编辑:我尝试了以下操作来获得触摸,认为 Apple 可能出于某种原因在按钮外部发送多点触控/触摸。没有骰子。它有时仍会返回 nil 索引路径。

 NSSet *touches = [event touchesForView:sender];

【问题讨论】:

您是否尝试过用CGPoint p = [sender convertPoint:CGPointZero toView:self.collectionView]; NSIndexPath *indexPath = [self.collectionView indexPathForItemAtPoint:p]; 表达观点的另一种常见方法,看看效果是否更好? 我刚试过;很难确定,因为它是一个难以重现的错误,但它似乎真的不再这样做了!我希望我知道为什么其他方法不那么可靠,但是如果我发现任何问题,我会将这个补丁放入并再次发布。 【参考方案1】:

indexPathForItemAtPoint: 如果“no item was found at the specified point”返回nil,这是最常见的情况,当点落在单元格之间的间距中时。有 3 个流布局属性通常用于影响单元格的间距:

minimumLineSpacing minimumInteritemSpacing sectionInset

当你得到一个nil 索引路径然后询问它的行时,它总是0,因此appState.colors[indexPath.row] 给你数组中的第一个颜色。


解决此问题的一种方法是遍历indexPathsForVisibleItems 中的所有单元格,并确定哪个包含中心点(如果有)或最接近它。最简单的方法是使用 - layoutAttributesForItemAtIndexPath:CGRectContainsPoint() 和一些简单的数学运算。

如果您获得nil 路径并且不采取任何操作,那么您的应用程序也可以简单地使用return

【讨论】:

这个答案解决了我的问题,这正是我在两个单元格之间的某个点上要求索引路径。我在 UICollectionView 上实现了一个名为 indexPathForCellNearestPoint 的类别:使用上面的提示,它可以工作。 @jszumski 您能否详细说明 layoutAttributesForItemAtIndexPath: 和 CGRectContainsPoint() 的精确用法?当试图找到最近的单元中心时,我们可以计算最小距离吗? for (NSIndexPath* path in [self indexPathsForVisibleItems]) cell = [self cellForItemAtIndexPath:path];距离 = powf(cell.center.x - point.x, 2) + powf(cell.center.y - point.y, 2);如果(距离 @Cindeselia 这完全取决于您的应用程序是否有意义。您能否创建一个包含更多细节的新问题并将其链接到此处?

以上是关于indexPathForItemAtPoint 偶尔返回 nil的主要内容,如果未能解决你的问题,请参考以下文章

宏实现奇数偶数位交换及offsetof

一个布尔递归函数,用于判断一个数字是不是在整数中出现偶数次

基础编程题之奇数位(偶数位)都是奇数(偶数)

为啥这个简单的 Web 服务器会被调用偶数次?

使用按位运算符查找每个偶数位是不是设置为 0

奇/偶递归函数中的分段错误