当superview有手势时,collectionView没有调用didSelectItemAtIndexPath

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

  1. initCollectionView然后添加到self.view
  2. 在self.view中使用addTapGesture
  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; } 

你需要设置tapGesture.cancelsTouchesInView = NO

根据你的逻辑你可能想要检查出delaysTouchesBegan也开始。

从Apple文档:

当此属性的值为false(默认值)时,视图将分析开始时的触摸事件并与接收器并行移动。 当属性的值为true时,窗口将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"); } } 

编辑2:也许关于手势识别器的最清晰的解释,以及如何在视图中添加时,它们如何工作:

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

如果日志中出现“doGesture”,那么它会按预期工作,因为您在整个视图上添加了轻击识别器。 如果你想要点击被识别,并且没有select被调用,你需要从你的抽头代码中调用didSelect。

 let locationInView: CGPoint = tapGesture.location(in: self.view) let locationInCollectionView: CGPoint = tapGesture.location(in: self.collectionView) if let indexPath: IndexPath = collectionView.indexPathForItem(at: locationInCollectionView) { collectionView.selectItem(at: indexPath, animated: true, scrollPosition: .centeredVertically) 

}

设置tapGesture.cancelsTouchesInView = NO

这允许触摸其他视图内的通过,如collectionView didSelectItemAtIndexPath

请注意,您还将获得tapGesture事件。 如果你想忽略当一个collectionViewCell被点击时,添加这个委托方法:

 -(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch{ CGPoint touchPoint = [touch locationInView:self.collectionView]; return ![self.collectionView hitTest:touchPoint withEvent:nil]; }