美文网首页iosiOS精華ios学习资料
iOS - UICollectionView 长按拖拽

iOS - UICollectionView 长按拖拽

作者: 态度哥 | 来源:发表于2016-08-17 17:56 被阅读2254次

    简单写了一个collectionview的拖拽效果,记录下.只是简单的实现了拖拽,其它都没有加

    实现思路:

    1. 首先给collectionview添加长按的手势
    2. 找到当前长按的cell, 截图保存为一个view(实际拖拽过程中是拖拽的这个view) ,然后隐藏原先的cell
    3. 拖拽截图的view,在拖拽的过程中和collectionview上已有的cell进行对比,交换位置,改变数据
    4. 拖拽结束之后,删除截图的view,显示最开始的cell

    具体代码

    • 创建一个继承UICollectionViewFlowLayout 的类,你也可以直接写在viewcontroller中.(名字随便写的)
    
    #import <UIKit/UIKit.h>
    
    @protocol DFZFBLayoutDelegate <NSObject>
    
    //去改变数据源
    - (void)moveDataItem:(NSIndexPath*)fromIndexPath toIndexPath:(NSIndexPath*)toIndexPath;
    
    @end
    
    @interface DFZFBLayout : UICollectionViewFlowLayout
    
    @property (nonatomic, assign) id<DFZFBLayoutDelegate> delegate;
    
    @end
    
    • .m中具体的实现
      • 这里只是简单的添加一个手势去做的,会慢慢改进.
    
    #import "DFZFBLayout.h"
    
    @interface DFZFBLayout ()<UIGestureRecognizerDelegate>
    
    @property (nonatomic, strong) UILongPressGestureRecognizer *longPress;
    @property (nonatomic, strong) NSIndexPath *currentIndexPath;    //当前的IndexPath
    @property (nonatomic, strong) UIView *mappingImageCell;         //拖动cell的截图
    
    @end
    
    @implementation DFZFBLayout
    
    - (id)initWithCoder:(NSCoder *)aDecoder{
        self = [super initWithCoder:aDecoder];
        if (self) {
            [self configureObserver];
        }
        return self;
    }
    
    - (instancetype)init{
        self = [super init];
        if (self) {
            [self configureObserver];
        }
        return self;
    }
    
    - (void)dealloc{
        [self removeObserver:self forKeyPath:@"collectionView"];
    }
    
    #pragma mark - setup
    
    - (void)configureObserver{
        [self addObserver:self forKeyPath:@"collectionView" options:NSKeyValueObservingOptionNew context:nil];
    }
    
    - (void)setUpGestureRecognizers{
        if (self.collectionView == nil) {
            return;
        }
        _longPress = [[UILongPressGestureRecognizer alloc]initWithTarget:self action:@selector(handleLongPress:)];
        _longPress.minimumPressDuration = 0.2f;
        _longPress.delegate = self;
        [self.collectionView addGestureRecognizer:_longPress];
    }
    
    #pragma mark - observer
    - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{
        if ([keyPath isEqualToString:@"collectionView"]) {
            [self setUpGestureRecognizers];
        }else{
            [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
        }
    }
    
    - (void)handleLongPress:(UILongPressGestureRecognizer*)longPress
    {
        switch (longPress.state) {
            case UIGestureRecognizerStateBegan:
            {
                CGPoint location = [longPress locationInView:self.collectionView];
                NSIndexPath* indexPath = [self.collectionView indexPathForItemAtPoint:location];
                if (!indexPath) return;
    
                self.currentIndexPath = indexPath;
                UICollectionViewCell* targetCell = [self.collectionView cellForItemAtIndexPath:self.currentIndexPath];
                //得到当前cell的映射(截图)
                UIView* cellView = [targetCell snapshotViewAfterScreenUpdates:YES];
                self.mappingImageCell = cellView;
                self.mappingImageCell.frame = cellView.frame;
                targetCell.hidden = YES;
                [self.collectionView addSubview:self.mappingImageCell];
                
                cellView.center = targetCell.center;
            }
                break;
            case UIGestureRecognizerStateChanged:
            {
                CGPoint point = [longPress locationInView:self.collectionView];
                //更新cell的位置
                self.mappingImageCell.center = point;
                NSIndexPath * indexPath = [self.collectionView indexPathForItemAtPoint:point];
                if (indexPath == nil )  return;
                if (![indexPath isEqual:self.currentIndexPath])
                {
                    //改变数据源
                    if ([self.delegate respondsToSelector:@selector(moveDataItem:toIndexPath:)]) {
                        [self.delegate moveDataItem:self.currentIndexPath toIndexPath:indexPath];
                    }
                    [self.collectionView moveItemAtIndexPath:self.currentIndexPath toIndexPath:indexPath];
                    self.currentIndexPath = indexPath;
                }
            }
                break;
            case UIGestureRecognizerStateEnded:
            {
                UICollectionViewCell *cell = [self.collectionView cellForItemAtIndexPath:self.currentIndexPath];
                
                [UIView animateWithDuration:0.25 animations:^{
                    self.mappingImageCell.center = cell.center;
                } completion:^(BOOL finished) {
                    [self.mappingImageCell removeFromSuperview];
                    cell.hidden           = NO;
                    self.mappingImageCell = nil;
                    self.currentIndexPath = nil;
                }];
            }
                break;
            default:
            {
                
            }
                break;
        }
        
        
    }
    
    @end
    

    应用

    • 在viewcontroller中代码:
    
     DFZFBLayout* layout = [[DFZFBLayout alloc]init];
        layout.delegate = self;
        //layout.dataSource = self;
        layout.minimumInteritemSpacing = 1;
        layout.minimumLineSpacing      = 1;
        layout.sectionInset = UIEdgeInsetsMake(1, 1, 1, 1);
        layout.headerReferenceSize = CGSizeMake(SCREEN_WIDTH, 40.f);
    //    layout.footerReferenceSize = CGSizeMake(SCREEN_WIDTH, 0.f);
    //    [layout setSectionInset:UIEdgeInsetsMake(0, 0,20,0)];
    
        
        myCollectionView = [[UICollectionView alloc]initWithFrame:CGRectZero collectionViewLayout:layout];
        myCollectionView.delegate = self;
        myCollectionView.dataSource = self;
        myCollectionView.backgroundColor = [UIColor whiteColor];
        [self.view addSubview:myCollectionView];
    

    效果

    嗨,我是效果图哦

    iOS9之后 提供了API 记录下,方便以后使用

    // Support for reordering
    - (BOOL)beginInteractiveMovementForItemAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(9_0); // returns NO if reordering was prevented from beginning - otherwise YES
    - (void)updateInteractiveMovementTargetPosition:(CGPoint)targetPosition NS_AVAILABLE_IOS(9_0);
    - (void)endInteractiveMovement NS_AVAILABLE_IOS(9_0);
    - (void)cancelInteractiveMovement NS_AVAILABLE_IOS(9_0);
    
    - (void)handlelongGesture:(UILongPressGestureRecognizer *)longGesture {
        //判断手势状态
        switch (longGesture.state) {
            case UIGestureRecognizerStateBegan:{
                //判断手势落点位置是否在路径上
                NSIndexPath *indexPath = [self.collectionView indexPathForItemAtPoint:[longGesture locationInView:self.collectionView]];
                if (indexPath == nil) {
                    break;
                }
                //在路径上则开始移动该路径上的cell
                [self.collectionView beginInteractiveMovementForItemAtIndexPath:indexPath];
            }
                break;
            case UIGestureRecognizerStateChanged:
                //移动过程当中随时更新cell位置
                [self.collectionView updateInteractiveMovementTargetPosition:[longGesture locationInView:self.collectionView]];
                break;
            case UIGestureRecognizerStateEnded:
                //移动结束后关闭cell移动
                [self.collectionView endInteractiveMovement];
                break;
            default:
                [self.collectionView cancelInteractiveMovement];
                break;
        }
    }
    
    - (BOOL)collectionView:(UICollectionView *)collectionView canMoveItemAtIndexPath:(NSIndexPath *)indexPath{
        //返回YES允许其item移动
        return YES;
    }
    
    - (void)collectionView:(UICollectionView *)collectionView moveItemAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath*)destinationIndexPath {
        //取出源item数据
        id objc = [_dataSource objectAtIndex:sourceIndexPath.item];
        //从资源数组中移除该数据
        [_dataSource removeObject:objc];
        //将数据插入到资源数组中的目标位置上
        [_dataSource insertObject:objc atIndex:destinationIndexPath.item];
    } 
    
    

    相关文章

      网友评论

      • Owl_City_Gx:lalalla
      • 程序员进阶:今天在写类似今日头条选择喜欢的话题,是两个组之间拖拽,比较伤脑筋
        3822821d26fb:@idhong你这个那个size相同多组的 如果一组一完了,就不能移回去了 怎么破
        liangdahong:https://github.com/asiosldh/BMDragCellCollectionView :smiley: 有现成的可以瞧瞧。
      • 2bc7cb8d69d6:在拖拽的时候弹出alterView了 结果crash了。。请问有什么办法处理吗 谢谢
        2bc7cb8d69d6:@英超联赛切尔西足球俱乐部 crash是数据没处理导致的。 - (void)longPress:(UILongPressGestureRecognizer *)longPressed UIGestureRecognizerStateBegan-->拖拽-->UIGestureRecognizerStateEnded 。现在就是在拖拽过程中,弹alter,后面的状态UIGestureRecognizerStateEnded没走了,UIGestureRecognizerStateFailed也没走。
        态度哥: @三哥当爹了 报的什么错

      本文标题:iOS - UICollectionView 长按拖拽

      本文链接:https://www.haomeiwen.com/subject/nvwmsttx.html