当超级视图有手势时,collectionView 没有调用 didSelectItemAtIndexPath

cod*_*ode 1 objective-c ios uitapgesturerecognizer uicollectionview

当 superview 有 tapGesture 时,collectionView 没有调用 didSelectItemAtIndexPath?这是为什么?
为什么它根据响应者链打印“doGesture”?

  1. initCollectionView 然后添加到 self.view
  2. 在 self.view 中添加TapGesture
  3. 单击 iPhone 中的项目。
  4. 不调用 didSelectItemAtIndexPath。

    - (void)viewDidLoad {
        [super viewDidLoad];
        UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
        self.collectionView = [[MyCollectionView alloc] initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height - 100) collectionViewLayout:flowLayout];
        [self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"abc"];
        self.collectionView.delegate = self;
        self.collectionView.dataSource = self;
        [self.view addSubview:self.collectionView];
    
        UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(doGesture)];
        tapGesture.delegate = self;
        [self.view addGestureRecognizer:tapGesture];
    }
    
    - (void)doGesture
    {
        NSLog(@"%@",@"doGesture");
    }
    
    - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
    {
        return 100;
    }
    
    - (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
    {
        NSLog(@"%@",@"didSelectItemAtIndexPath");
    }
    
    - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
    {
        UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"abc" forIndexPath:indexPath];
        if (indexPath.row %2==0) {
            cell.backgroundColor = [UIColor redColor];
        } else{
            cell.backgroundColor = [UIColor grayColor];
        }
        return cell;
    }
    
    Run Code Online (Sandbox Code Playgroud)

Geo*_*iev 6

您需要设置tapGesture.cancelsTouchesInView = NO.

根据您的逻辑,您可能也想退房delaysTouchesBegan

来自苹果文档:

当此属性的值为 false(默认值)时,视图会分析开始并与接收器并行移动的触摸事件。当该属性的值为真时,窗口会暂停将 UITouchPhaseBegan 阶段中的触摸对象传递给视图。如果手势识别器随后识别出其手势,则丢弃这些触摸对象。然而,如果手势识别器不能识别它的手势,窗口将这些对象以 touchesBegan( :with:) 消息(可能还有后续的 touchesMoved( :with:) 消息来通知它触摸)传递给视图' 当前位置)。将此属性设置为 true 以防止视图处理 UITouchPhaseBegan 阶段中可能被识别为该手势的一部分的任何触摸。

编辑: 为了完整起见,当用户点击集合视图时,我添加了用于过滤手势识别器处理的代码片段。我的方法与@DonMag 的回答中提到的方法不同。

- (void)doGesture:(UIGestureRecognizer*) sender
{    
    CGPoint locationInView = [sender locationOfTouch:0 inView:self.view];
    CGPojnt convertedLocation = [self.collectionView convertPoint:location fromView:self.view];

    // from Apple doc
    // Returns a Boolean value indicating whether the receiver contains the specified point.
    if (![self.collectionView pointInside:convertedLocation withEvent:nil])
    {
      NSLog(@"%@",@"doGesture");        
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑 2:当添加到视图中时,也许是关于手势识别器及其工作方式的最清晰的解释:

每个手势识别器都与一个视图相关联。相比之下,一个视图可以有多个手势识别器,因为一个视图可能会响应许多不同的手势。要让手势识别器识别特定视图中发生的触摸,您必须将手势识别器附加到该视图。当用户触摸该视图时,手势识别器会收到一条消息,指出在视图对象之前发生了触摸。结果,手势识别器可以代表视图响应触摸。