为什么在我的UIPanGestureRecognizer上调用UILongPressGestureRecognizer方法?

时间:2013-12-27 01:07:28

标签: ios objective-c uigesturerecognizer uipangesturerecognizer

我有一个自定义的UITableViewCell,它有一个平移手势识别器:

// CustomCell.m

- (id)initWithCoder:(NSCoder *)aDecoder {
    self = [super initWithCoder:aDecoder];
    if (self) {
        // Initialization code

        // Add a pan recognizer
        UIGestureRecognizer* recognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)];
        recognizer.delegate = self;
        [self addGestureRecognizer:recognizer];
    }
    return self;
}

我正在使用平移手势来检测用户是否以任何水平方式滑动单元格,然后单元格根据单元格的滑动程度执行一些不同的操作。细胞行为的这个方面就像我想要的那样。

但我刚刚发现如果我按下单元格并且不向任何方向滑动,应用程序会因为调用UILongPressGestureRecognizer而崩溃,但我的应用程序中根本没有UILongPressGestureRecognizer。 为什么在我的UIPanGestureRecognizer上调用UILongPressGestureRecognizer方法?

以下是我的Pan手势处理方法:

#pragma mark - Horizontal pan gesture methods

- (BOOL)gestureRecognizerShouldBegin:(UIPanGestureRecognizer *)gestureRecognizer {
    CGPoint translation = [gestureRecognizer translationInView:[self superview]];
    // Check for horizontal gesture
    if (fabsf(translation.x) > fabsf(translation.y)) {
        return YES;
    }
    return NO;
}

#pragma mark - Handel pan gesture

- (void)handlePan:(UIPanGestureRecognizer *)recognizer {
    // 1
    if (recognizer.state == UIGestureRecognizerStateBegan) {
        // if the gesture has just started, record the current centre location
        originalCenter = self.center;
    }

    // 2
    if (recognizer.state == UIGestureRecognizerStateChanged) {

        // translate the center
        CGPoint translation = [recognizer translationInView:self];
        self.center = CGPointMake(originalCenter.x + translation.x, originalCenter.y);

        // determine whether the item has been dragged far enough to initiate a delete / complete / edit
        editOnDragRelease = self.frame.origin.x < -self.frame.size.width / 4;
        deleteOnDragRelease = self.frame.origin.x < -self.frame.size.width / 1.5;
        markCompleteOnDragRelease = self.frame.origin.x > self.frame.size.width / 8;
    }

    // 3
    if (recognizer.state == UIGestureRecognizerStateEnded) {
        // the frame this cell would have had before being dragged
        CGRect originalFrame = CGRectMake(0, self.frame.origin.y, self.bounds.size.width, self.bounds.size.height);

        if (!deleteOnDragRelease || !editOnDragRelease) {
            // if the item is not being deleted/edited, snap back to the original location
            [UIView animateWithDuration:0.2 animations:^{
                self.frame = originalFrame;
            }];
        }

        // Edit
        if (!deleteOnDragRelease && editOnDragRelease) {
            [self.delegate editItem:self.item];
        }

        // Delete
        if (deleteOnDragRelease) {
            [self.delegate itemDeleted:self.item];
        }

        // Toggle color
        if (markCompleteOnDragRelease) {
            [self.delegate toggleColorForItem:self.item];
        }
    }
}

我在崩溃日志中遇到的错误是当我选择一个单元格但不以任何方式滑动/平移时:

-[UILongPressGestureRecognizer translationInView:]: unrecognized selector sent to instance 0x1093327c0
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UILongPressGestureRecognizer translationInView:]: unrecognized selector sent to instance 0x1093327c0'

非常感谢任何帮助!

2 个答案:

答案 0 :(得分:3)

崩溃可能发生在gestureRecognizerShouldBegin:委托方法中,该方法被调用任何手势识别器,此类实例是委托。

这包括iOS可能正在创建的手势识别器,并将自己分配给基础标准UITableViewCell

iOS必须在单元格中添加UILongPressGestureRecognizer(供自己使用),并且会为您调用委托方法以及UIPanGestureRecognizer

由于UILongPressGestureRecognizer没有translationInView:方法,因此导致“无法识别的选择器”崩溃。

至少,您可以检查gestureRecognizer参数是否实际为UIPanGestureRecognizer,如果不是,则不执行任何操作,只返回YES

另请注意,即使您已将gestureRecognizerShouldBegin:方法的参数类型声明为UIPanGestureRecognizer *,但这实际上并不会阻止任何UIGestureRecognizer *调用它(即。将参数类型保留为通用UIGestureRecognizer *,以便明确含义和含义。

- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer 
{
    //if gestureRecognizer is not a UIPanGestureRecognizer, let it go...
    if (! [gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]])
    {
        return YES;
    }

    //Cast the gestureRecognizer as a UIPanGestureRecognizer so
    //compiler knows and checks what we're doing...
    UIPanGestureRecognizer *pgr = (UIPanGestureRecognizer *)gestureRecognizer;

    CGPoint translation = [pgr translationInView:[self superview]];
    // Check for horizontal gesture
    if (fabsf(translation.x) > fabsf(translation.y)) {
        return YES;
    }
    return NO;
}

答案 1 :(得分:0)

UITableViewCell有一个内置的UILongPressGestureRecognizer,它本身就是手势委托。因此,当用户点击该行并且tableView:shouldShowMenuForRowAtIndexPath:方法返回YES时,它可以显示编辑菜单(复制,粘贴等)。

这里的问题就像@Anna在gestureRecognizerShouldBegin方法中所说的那样。内置(父类)UITableViewCell's UILongPressGestureRecognizer共享您分配给Pan手势的同一代理。