不要在特定位置使用长按手势移动表格视图单元格

Posted

技术标签:

【中文标题】不要在特定位置使用长按手势移动表格视图单元格【英文标题】:Don't Move Table View Cells with a Long Press Gesture on specific position 【发布时间】:2015-05-09 10:45:42 【问题描述】:

我已经在我的应用程序中完全实现了 UILongGesture,它通过拖放来交换单元格值。现在我的要求是,如果我将第一行与最后一行一起移动,那么第一行应该保持在第一个位置意味着不想改变位置。

我尝试了一大堆代码并浪费了我的时间但无法获得结果。下面是我的代码。

- (IBAction)longPressGestureRecognized:(id)sender

UILongPressGestureRecognizer *longGesture = (UILongPressGestureRecognizer *)sender;
UIGestureRecognizerState state = longGesture.state;
CGPoint location = [longGesture locationInView:self.tblTableView];
NSIndexPath *indexpath = [self.tblTableView indexPathForRowAtPoint:location];

static UIView *snapshotView = nil;
static NSIndexPath *sourceIndexPath = nil;

switch (state) 
    case UIGestureRecognizerStateBegan:
        if (indexpath) 
            sourceIndexPath = indexpath;
            UITableViewCell *cell = [self.tblTableView cellForRowAtIndexPath:indexpath];
            snapshotView = [self customSnapshotFromView:cell];
            __block CGPoint center = cell.center;
            snapshotView.center = center;
            snapshotView.alpha = 0.0;
            [self.tblTableView addSubview:snapshotView];
            [UIView animateWithDuration:0.25 animations:^

                center.y = location.y;
                snapshotView.center = center;
                snapshotView.transform = CGAffineTransformMakeScale(1.05, 1.05);
                snapshotView.alpha = 0.98;

                cell.alpha = 0.0;

             completion:^(BOOL finished) 
                cell.hidden = YES;
            ];
        
        break;

    case UIGestureRecognizerStateChanged: 
        CGPoint center = snapshotView.center;
        center.y = location.y;
        snapshotView.center = center;

        if (indexpath && ![NSIndexPath isEqual:sourceIndexPath]) 

    [self.namesArray exchangeObjectAtIndex:indexpath.row withObjectAtIndex:sourceIndexPath.row];

            [self.tblTableView moveRowAtIndexPath:sourceIndexPath toIndexPath:indexpath];

            sourceIndexPath = indexpath;

            NSIndexPath *indexPathOfLastItem =[NSIndexPath indexPathForRow:([self.namesArray count] - 1) inSection:0];
            NSLog(@"last :::: %@",indexPathOfLastItem);

            if (indexpath==indexPathOfLastItem) 
                [self.namesArray exchangeObjectAtIndex:indexPathOfLastItem.row withObjectAtIndex:sourceIndexPath.row];
                [self.tblTableView moveRowAtIndexPath:indexPathOfLastItem toIndexPath:0];

                UITableViewCell *cell = [self.tblTableView cellForRowAtIndexPath:sourceIndexPath];
                cell.hidden = NO;
                cell.alpha = 0.0;
            
        
        break;
    

    default: 
        UITableViewCell *cell = [self.tblTableView cellForRowAtIndexPath:sourceIndexPath];
        cell.hidden = NO;
        cell.alpha = 0.0;

        [UIView animateWithDuration:0.25 animations:^

            snapshotView.center = cell.center;
            snapshotView.transform = CGAffineTransformIdentity;
            snapshotView.alpha = 0.0;
            cell.alpha = 1.0;

         completion:^(BOOL finished) 

            sourceIndexPath = nil;
            [snapshotView removeFromSuperview];
            snapshotView = nil;

        ];

        break;
    


编辑:我遇到的是细胞没有交换我想要的但它被隐藏了。这是图片:Image1 和 Image2

【问题讨论】:

if (indexpath && ![NSIndexPath isEqual:sourceIndexPath]) NSIndexPath 在那里做什么?似乎不对。也许,if (indexpath && ![indexpath isEqual:sourceIndexPath]) 【参考方案1】:

首先,我认为您不应该在UIGestureRecognizerStateChanged 中进行行交换,而应在UIGestureRecognizerStateEnded 中进行。当您长按并在屏幕上移动手指时,UIGestureRecognizerStateChanged 会被快速处理(很多次)。所以这会导致行交换代码运行多次,我猜这不是你的意图。 UIGestureRecognizerStateBeganUIGestureRecognizerStateEnded 每次长按运行一次。

我会将以下三行代码保留在UIGestureRecognizerStateChanged 中,并将其余代码移至UIGestureRecognizerStateEnded

CGPoint center = snapshotView.center;
center.y = location.y;
snapshotView.center = center;

UIGestureRecognizerStates 如下:

UIGestureRecognizerStatePossible,   // the recognizer has not yet recognized its gesture, but may be evaluating touch events. this is the default state
UIGestureRecognizerStateBegan,      // the recognizer has received touches recognized as the gesture. the action method will be called at the next turn of the run loop
UIGestureRecognizerStateChanged,    // the recognizer has received touches recognized as a change to the gesture. the action method will be called at the next turn of the run loop
UIGestureRecognizerStateEnded,      // the recognizer has received touches recognized as the end of the gesture. the action method will be called at the next turn of the run loop and the recognizer will be reset to UIGestureRecognizerStatePossible
UIGestureRecognizerStateCancelled,  // the recognizer has received touches resulting in the cancellation of the gesture. the action method will be called at the next turn of the run loop. the recognizer will be reset to UIGestureRecognizerStatePossible
UIGestureRecognizerStateFailed,     // the recognizer has received a touch sequence that can not be recognized as the gesture. the action method will not be called and the recognizer will be reset to UIGestureRecognizerStatePossible

我相信在你的状态机逻辑中覆盖更多这些状态会更好,而不是使用switchs default:

【讨论】:

我在 UIGestureRecognizerStateEnded 中尝试过,但没有任何效果。 Nij 你能把你的代码上传到 gitHub 并在这里发布 reprisotory 吗?这么多代码很难说清楚【参考方案2】:

当你的手指在动画过程中离开屏幕时,ios 返回gesture.state = UIGestureRecognizerStatePossible

所以记得处理那个手势!

【讨论】:

以上是关于不要在特定位置使用长按手势移动表格视图单元格的主要内容,如果未能解决你的问题,请参考以下文章

自定义表格视图单元格中特定元素的手势

删除特定表格视图单元格的手势

在表格视图单元格中使用 UILongPressGestureRecognizer 时出现问题

长按选择的 Swift 3.0 表格视图单元格

将手势识别器添加到表格单元格中的图像视图

长按手势操作表删除单元格