【问题标题】:My gesture recognizer is attached to the wrong view我的手势识别器附加到错误的视图
【发布时间】:2014-06-08 19:20:46
【问题描述】:

我有一个 UICollectionView,它的元素可以在屏幕上拖放。我使用 UILongPressGestureRecognizer 来处理拖动。我在collectionView:cellForItemAtIndexPath: 方法中将此识别器附加到集合视图单元格。但是,识别器的 view 属性偶尔会返回 UIView 而不是 UICollectionViewCell。我需要一些仅在 UICollectionViewCell 上的方法/属性,而当返回 UIView 时我的应用程序崩溃。

为什么附加到单元格的识别器会返回一个普通的 UIView?

附加识别器

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath 
{
    EXSupplyCollectionViewCell *cell = (EXSupplyCollectionViewCell *)[collectionView dequeueReusableCellWithReuseIdentifier:CellIdentifier forIndexPath:indexPath];
    UILongPressGestureRecognizer *longPressRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:cell action:nil];
    longPressRecognizer.delegate = self;
    [cell addGestureRecognizer:longPressRecognizer];
    return cell;
}

处理手势

我使用带有 switch 语句的方法来调度长按的不同状态。

- (void)longGestureAction:(UILongPressGestureRecognizer *)gesture {
    UICollectionViewCell *cell = (UICollectionViewCell *)[gesture view];
    switch ([gesture state]) {
        case UIGestureRecognizerStateBegan:
            [self longGestureActionBeganOn:cell withGesture:gesture];
            break;
        //snip
        default:
            break;
    }
}

如果cell 实际上是UICollectionViewCell,则调用longGestureActionBeganOn:withGesture 时,手势的其余部分将完美执行。如果不是,那么它会在尝试确定应该是单元格的索引路径时中断。

第一次出现中断

- (void)longGestureActionBeganOn:(UICollectionViewCell *)cell withGesture:(UILongPressGestureRecognizer *)gesture
{
    NSIndexPath *indexPath = [self.collectionView indexPathForCell:cell]; // unrecognized selector is sent to the cell here if it is a UIView
    [self.collectionView setScrollEnabled:NO];
    if (indexPath != nil) {
        // snip
    }
}

我还将 UICollectionViewCell 特有的其他属性用于手势的其他状态。有什么方法可以保证识别器总是将我分配给它的视图返回给我?

【问题讨论】:

  • 问题可能与单元格重用有关,如果要显示一个单元格,您的代码最终会在每个单元格中使用多个手势识别器。从理论上讲,这应该只触发多次动作,而不是混淆视图。无论如何,我会推荐add the gestureRecognizer to the collectionView
  • @MatthiasBauch 我在prepareForReuse 方法中删除了手势识别器,以防止多次添加识别器,它似乎解决了我的问题。如果您想根据您的评论做出回答,我会继续并将其标记为解决方案。

标签: ios objective-c uigesturerecognizer


【解决方案1】:

像 UICollectionView 和 UITableView 这样的视图将重用它们的单元格。如果你盲目地在collectionView:cellForItemAtIndexPath: 中添加一个gestureRecognizer,那么每次重新加载单元格时都会添加一个新的。如果你稍微滚动一下,你最终会在每个单元格上看到几十个手势识别器。

除了多次调用gestureRecognizer的动作之外,理论上这不会引起任何问题。但是 Apple 在单元重用方面使用了大量的性能优化,因此可能会出现一些问题。

解决问题的首选方法是add the gestureRecognizer to the collectionView

另一种方法是检查单元格上是否已经有一个gestureRecognizer,如果没有,则只添加一个新的。或者您使用您找到的解决方案并删除单元格的prepareForReuse 中的gestureRecognizer。 当您使用后一种方法时,您应该检查您是否删除(或测试)正确的方法。您不想删除系统为您添加的手势识别器。 (我不确定 iOS 当前是否使用此功能,但为了让您的应用在未来得到验证,您可能需要坚持此最佳实践。)

【讨论】:

  • 检查这种方式: if ([cell.gestureRecognizers count]) { // 识别器已经在单元格中找到 }
【解决方案2】:

我遇到了与 Long-Touch 相关的类似问题。 我最终做的是覆盖 UICollectionViewCell.PrepareForReuse 并取消附加到我的视图的 UIGestureRecognizers。所以每次我的细胞被回收时,长按事件都会被取消。

See this answer

【讨论】:

    猜你喜欢
    • 2017-04-21
    • 1970-01-01
    • 2013-09-29
    • 1970-01-01
    • 1970-01-01
    • 2011-12-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多