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的主要内容,如果未能解决你的问题,请参考以下文章