Exchange position of cells by gesture

随声附和 提交于 2020-01-04 01:53:16

问题


I have UICollectionView in which I have a prototype cell and UIImageView in it.I am displaying random images in UICollectionView.

Now I want to exchange position of UIImageView by swiping it to near cell.I have tried swipe gesture and long press gesture.Code is given below which I have done:

- (IBAction)LongPress:(UILongPressGestureRecognizer *)sender
{
    if (sender.state != UIGestureRecognizerStateEnded) 
    {
        return;
    }
    CGPoint p = [sender locationInView:self.collectionView];

    NSIndexPath *indexPath = [self.coll_out indexPathForItemAtPoint:p];
    if (indexPath == nil)
    {
        NSLog(@"couldn't find index path");            
    }
    else 
    {
        // get the cell at indexPath (the one you long pressed)
        UICollectionViewCell* cell =[self.coll_out cellForItemAtIndexPath:indexPath];
        // do stuff with the cell
    }
}

And also tried delegate method:

- (void)moveItemAtIndexPath:(NSIndexPath *)indexPath toIndexPath:(NSIndexPath *)newIndexPath
{
    NSMutableArray *item1=[arr_final objectAtIndex:indexPath.section];
    NSMutableArray *item2=[arr_final objectAtIndex:newIndexPath.section];
    NSLog(@"%@ %@",item1,item2);
    NSString *index = [item1 objectAtIndex:indexPath.item];
    [item1 removeObjectAtIndex:indexPath.item];
    [item2 insertObject:index atIndex:newIndexPath.item];
}

Functionality is just like drag and drop. I have seen examples of

  • LXReorderableCollectionViewFlowLayout
  • HTKDragAndDropCollectionViewLayout

Please give me the right way and code for swiping to near cell. Thanks...


回答1:


Actually I've been using LXReorderableCollectionViewFlowLayout and it perfectly suits for you and it also has an example in their repository. At first I don't suggest you to use swipe gesture because it highly conflicts with internal gesture handling for UICollectionView, but if you sure you need it, you have to implement delegation methods for added gesture and resolve simultaneous gestures as it's doing LXReordableCollectionViewFlowLayout:

- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
    if ([self.panGestureRecognizer isEqual:gestureRecognizer]) {
        return (self.selectedItemIndexPath != nil);
    }
    return YES;
}

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
    if ([self.longPressGestureRecognizer isEqual:gestureRecognizer]) {
        return [self.panGestureRecognizer isEqual:otherGestureRecognizer];
    }

    if ([self.panGestureRecognizer isEqual:gestureRecognizer]) {
        return [self.longPressGestureRecognizer isEqual:otherGestureRecognizer];
    }

    return NO;
}

Anyways I don't suggest you to reimplement what's done in LXReordableCollectionViewFlowLayout and just use it for your needs. If you're using Storyboard you need to place your UICollectionView into your UIViewController and change default UICollectionViewFlowLayout class into LXReorderableCollectionViewFlowLayout just like that Also your delegate for UICollectionView should conform for the next protocols: LXReorderableCollectionViewDataSource (extends UICollectionViewDataSource) and LXReorderableCollectionViewDelegateFlowLayout (extends UICollectionViewDelegateFlowLayout) those allows you to use your class. For your needs it's enough to provide just next methods:

- (void)collectionView:(UICollectionView *)collectionView itemAtIndexPath:(NSIndexPath *)fromIndexPath willMoveToIndexPath:(NSIndexPath *)toIndexPath {
    id from = [items objectAtIndex:fromIndexPath.item];
    id to = [items objectAtIndex:toIndexPath.item];

    [items replaceObjectAtIndex:fromIndexPath.item withObject:to];
    [items replaceObjectAtIndex:toIndexPath.item withObject:from];;
}

- (BOOL)collectionView:(UICollectionView *)collectionView canMoveItemAtIndexPath:(NSIndexPath *)indexPath
{
    return YES;
}

- (BOOL)collectionView:(UICollectionView *)collectionView itemAtIndexPath:(NSIndexPath *)fromIndexPath canMoveToIndexPath:(NSIndexPath *)toIndexPath
{
    return YES;
}

To have exactly your needed behavior you have to go inside LXReorderableCollectionViewFlowLayout class and change invalidateLayoutIfNecessary method so it perform another kind of update rather than it did before:

- (void)invalidateLayoutIfNecessary {
    NSIndexPath *newIndexPath = [self.collectionView indexPathForItemAtPoint:self.currentView.center];
    NSIndexPath *previousIndexPath = self.selectedItemIndexPath;

    if ((newIndexPath == nil) || [newIndexPath isEqual:previousIndexPath]) {
        return;
    }

    if ([self.dataSource respondsToSelector:@selector(collectionView:itemAtIndexPath:canMoveToIndexPath:)] &&
        ![self.dataSource collectionView:self.collectionView itemAtIndexPath:previousIndexPath canMoveToIndexPath:newIndexPath]) {
        return;
    }

    self.selectedItemIndexPath = newIndexPath;

    if ([self.dataSource respondsToSelector:@selector(collectionView:itemAtIndexPath:willMoveToIndexPath:)]) {
        [self.dataSource collectionView:self.collectionView itemAtIndexPath:previousIndexPath willMoveToIndexPath:newIndexPath];
    }

    __weak typeof(self) weakSelf = self;
    [self.collectionView performBatchUpdates:^{
        __strong typeof(self) strongSelf = weakSelf;
        if (strongSelf) {
            // NOTE: cells swipe
            [strongSelf.collectionView moveItemAtIndexPath:previousIndexPath toIndexPath:newIndexPath];
            [strongSelf.collectionView moveItemAtIndexPath:newIndexPath toIndexPath:previousIndexPath];

            // NOTE: it was here previously
            // [strongSelf.collectionView deleteItemsAtIndexPaths:@[ previousIndexPath ]];
            // [strongSelf.collectionView insertItemsAtIndexPaths:@[ newIndexPath ]];
        }
    } completion:^(BOOL finished) {
        __strong typeof(self) strongSelf = weakSelf;
        if ([strongSelf.dataSource respondsToSelector:@selector(collectionView:itemAtIndexPath:didMoveToIndexPath:)]) {
            [strongSelf.dataSource collectionView:strongSelf.collectionView itemAtIndexPath:previousIndexPath didMoveToIndexPath:newIndexPath];
        }
    }];
}

It works well for cells which is near you initial item, but once your card moved it could be misleading for user where to move it next, anyways just try it and see how it's going on. Remember you could control available movement for item by collectionView:itemAtIndexPath:canMoveToIndexPath: method.

Hope this help you.



来源:https://stackoverflow.com/questions/34491561/exchange-position-of-cells-by-gesture

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!