通过手势交换细胞的位置 [英] Exchange position of cells by gesture

查看:168
本文介绍了通过手势交换细胞的位置的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有 UICollectionView ,其中有一个原型单元格,其中包含 UIImageView 。我正在显示随机图像 UICollectionView



现在我要交换 UIImageView

   - (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(@找不到索引路径);
}
else
{
//获取indexPath上的单元格(您长按的单元)
UICollectionViewCell * cell = [self.coll_out cellForItemAtIndexPath:indexPath];
//用单元格
}
}

并且还尝试了委托方法:

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

功能就像拖放。我看过





  • 您的UICollectionView代理也应符合下一个协议:LXReorderableCollectionViewDataSource(扩展UICollectionViewDataSource)和LXReorderableCollectionViewDelegateFlowLayout(扩展UICollectionViewDelegateFlowLayout),这些允许您使用您的类。对于您的需要,只需提供以下方法即可:

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

    要完全符合您需要的行为,您必须在LXReorderableCollectionViewFlowLayout类中进行更改, code> invalidateLayoutIfNecessary 方法,所以它执行另一种更新,而不是之前:

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

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

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

    self.selectedItemIndexPath = newIndexPath;

    if([self.dataSource responsesToSelector:@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){
    //注意:单元格滑动
    [strongSelf.collectionView moveItemAtIndexPath:previousIndexPath toIndexPath:newIndexPath];
    [strongSelf.collectionView moveItemAtIndexPath:newIndexPath toIndexPath:previousIndexPath];

    //注意:以前是
    // [strongSelf.collectionView deleteItemsAtIndexPaths:@ [previousIndexPath]];
    // [strongSelf.collectionView insertItemsAtIndexPaths:@ [newIndexPath]];
    }
    }完成:^(BOOL完成){
    __strong typeof(self)strongSelf = weakSelf;
    if([strongSelf.dataSource respondToSelector:@selector(collectionView:itemAtIndexPath:didMoveToIndexPath :)]){
    [strongSelf.dataSource collectionView:strongSelf.collectionView itemAtIndexPath:previousIndexPath didMoveToIndexPath:newIndexPath];
    }
    }];
    }

    它适用于靠近初始项目的单元格,但一旦您的卡移动它可能会误导用户下一步移动它,反正只是尝试看看它是怎么回事。记住,您可以通过 collectionView:itemAtIndexPath:canMoveToIndexPath:方法来控制项目的可用移动。



    希望这可以帮助您。


    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

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

    解决方案

    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.

    这篇关于通过手势交换细胞的位置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆