为啥 UICollectionView 在滚动其单元格的滚动视图后不再调用 didSelectItemAtIndexPath ?
Posted
技术标签:
【中文标题】为啥 UICollectionView 在滚动其单元格的滚动视图后不再调用 didSelectItemAtIndexPath ?【英文标题】:why UICollectionView not calling didSelectItemAtIndexPath any more after scrolling the scrollView of it's cells?为什么 UICollectionView 在滚动其单元格的滚动视图后不再调用 didSelectItemAtIndexPath ? 【发布时间】:2014-06-19 07:44:14 【问题描述】:我正在使用UICollectionView
来展示一些产品。在自定义UICollectionViewCell
中,有一个自定义UIScrollView
,里面有一些图片可以让用户快速预览。
要将轻按手势从UIScrollView
转发到UICollectionViewCell
,我将覆盖与触摸相关的方法,如下所示:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
if (!self.dragging)
NSLog(@"Began ==>");
[self.nextResponder touchesBegan:touches withEvent:event];
else
[super touchesBegan:touches withEvent:event];
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
if (!self.dragging)
NSLog(@"Moved ==>");
[self.nextResponder touchesMoved:touches withEvent:event];
else
[super touchesMoved:touches withEvent:event];
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
if (!self.dragging)
NSLog(@"Ended ==>");
[self.nextResponder touchesEnded:touches withEvent:event];
else
[super touchesEnded:touches withEvent:event];
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
if (!self.dragging)
NSLog(@"Cancelled ==>");
[self.nextResponder touchesCancelled:touches withEvent:event];
else
[super touchesCancelled:touches withEvent:event];
有时它在某些情况下不起作用。例如,第一次加载UICollectionView
时,点击时可以调用didSelectItemAtIndexPath
方法,但滚动或点击后,不再调用该方法,即使您尝试重新加载UICollectionView
,也是还是行不通。
我尝试在UICollectionViewCell
的触摸方法中记录消息,触摸和事件被转发。但是,如果单元格获得手势,为什么会调用UICollectionView
的didSelectItemAtIndexPath
呢?
任何建议将不胜感激。
更新:
1.UICollectionViewCell
是从nib文件中加载的。
【问题讨论】:
【参考方案1】:如果您要定位特定对象,则使用 nextResponder 不是一个好主意。正如您所看到的,响应者链可能会发生变化,您可能并不总是得到您期望的对象。为什么会发生这种情况可能有多种原因,但无论如何您都应该在这种情况下使用更可靠的方法。
由于UIScrollView
是UICollectionViewCell
的子视图,您可以直接将事件传递给您的超级视图[self.superview touchesMoved:touched withEvent:event];
您在执行此操作时需要牢记视图层次结构,并且可能需要调用超级视图的超级视图到达细胞。
另外,我不建议使用触摸来拦截用户交互。我强烈推荐使用 UIGestureRecognizers,因为这将提供更好更一致的功能。
【讨论】:
我尝试使用self.superview
。它也不可靠。实际上,手势被转发到单元格。但是没有调用 didselect 方法。很奇怪。【参考方案2】:
你应该总是调用超级方法。
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
[super touchesBegan:touches withEvent:event];
NSLog(@"Began ==>");
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
[super touchesMoved:touches withEvent:event];
NSLog(@"Moved ==>");
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
[super touchesEnded:touches withEvent:event];
NSLog(@"Ended ==>");
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
[super touchesCancelled:touches withEvent:event];
NSLog(@"Cancelled ==>");
【讨论】:
谢谢。我的意思是,我知道,但你让我检查,我错过了touchesCancelled
超级调用,它在滚动一点后随机地杀死了我的触摸处理。据推测,触摸处于半处理状态。
Not true “如果您在不调用 super 的情况下重写此方法(一种常见的使用模式),您还必须重写其他处理触摸事件的方法,如果只是作为存根(空)实现。” developer.apple.com/documentation/uikit/uiresponder/…
不确定:“如果您在不调用 super 的情况下覆盖此方法(一种常见的使用模式),那么您还必须覆盖处理触摸事件的其他方法,如果只是作为存根(空)实现。” developer.apple.com/documentation/uikit/uiresponder/…
不确定,developer.apple.com/documentation/uikit/uiresponder/…
不正确,如果您不调用其中的超级之一,则必须覆盖其余部分并执行相同操作(来自苹果文档)。【参考方案3】:
其实是因为self.dragging
的理解。
转发点击手势的正确方法如下:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
[self.nextResponder touchesBegan:touches withEvent:event];
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
[self.nextResponder touchesMoved:touches withEvent:event];
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
if (!self.dragging)
[self.nextResponder touchesEnded:touches withEvent:event];
else
[super touchesEnded:touches withEvent:event];
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
[self.nextResponder touchesCancelled:touches withEvent:event];
【讨论】:
以上是关于为啥 UICollectionView 在滚动其单元格的滚动视图后不再调用 didSelectItemAtIndexPath ?的主要内容,如果未能解决你的问题,请参考以下文章
为啥第一次滚动到另一个 UITableView 中的 UICollectionView 中的 UITableView 不加载数据?