【问题标题】: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 的触摸方法中记录消息,触摸和事件被转发。但是,如果单元格获得手势,为什么会调用UICollectionViewdidSelectItemAtIndexPath 呢?

任何建议将不胜感激。

更新: 1.UICollectionViewCell是从nib文件中加载的。

【问题讨论】:

    标签: ios uiscrollview uicollectionview uicollectionviewcell uiresponder


    【解决方案1】:

    如果您要定位特定对象,则使用 nextResponder 不是一个好主意。正如您所看到的,响应者链可能会发生变化,您可能并不总是得到您期望的对象。为什么会发生这种情况可能有多种原因,但无论如何您都应该在这种情况下使用更可靠的方法。

    由于UIScrollViewUICollectionViewCell 的子视图,您可以直接将事件传递给您的超级视图[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/…
    • 不正确,如果您不调用其中的超级之一,则必须覆盖其余部分并执行相同操作(来自苹果文档)。
    【解决方案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];
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-22
      相关资源
      最近更新 更多