当superview具有手势

时间:2017-02-21 16:20:03

标签: ios objective-c uicollectionview uitapgesturerecognizer

当superview有tapGesture时,

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;
    }
    

3 个答案:

答案 0 :(得分:3)

您需要设置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: 在视图中添加时,可能是关于手势识别器以及它们如何工作的最清晰的解释:

  

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

答案 1 :(得分:0)

设置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];
}

答案 2 :(得分:0)

如果" doGesture"出现在日志中,然后它按预期工作,因为您在整个视图的顶部添加了点击识别器。如果你想要识别水龙头并选择要调用,你需要自己从你的点击代码中调用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)

}