iOS 拖拽排序实现

作者: 马大俊不是啥好人 | 来源:发表于2016-11-25 17:27 被阅读365次

    老早之前说要做这个,主要是看了微博的一个转发,然后发现其实系统已经有自带的功能了。不管怎么样,先写一下基于UIColloctionView的拖曳排序。

    在iOS 9之前需要手动截图cell并进行拖曳计算,iOS 9之后存在两个delegate方法

    -(BOOL)collectionView:(UICollectionView *)collectionView canMoveItemAtIndexPath:(NSIndexPath *)indexPath
    {
        return YES;
    }
    
    - (void)collectionView:(UICollectionView *)collectionView moveItemAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath*)destinationIndexPath {
        id objc = [_arr objectAtIndex:sourceIndexPath.item];
        [_arr removeObject:objc];
        [_arr insertObject:objc atIndex:destinationIndexPath.item];
    }
    

    实现这两个方法就能实现拖曳排序。一步步来。
    首先新建一个UIColloctionViewCell的子类

    MoveCollectionViewCell.png
    //
    //  MoveCollectionViewCell.h
    //  MJChangeItem
    //
    //  Created by 马家俊 on 16/12/12.
    //  Copyright © 2016年 MJJ. All rights reserved.
    //
    
    #import <UIKit/UIKit.h>
    
    @protocol MoveCollectionViewCellDelegate <NSObject>
    - (void)GesturePressDelegate:(UIGestureRecognizer *)gestureRecognizer;
    @end
    @interface MoveCollectionViewCell : UICollectionViewCell
    {
        __weak id<MoveCollectionViewCellDelegate>m_MoveCollectionViewCellDelegate;
    }
    @property (nonatomic, weak) id<MoveCollectionViewCellDelegate> p_MoveCollectionViewCellDelegate;
    @property (nonatomic, strong) NSString* cellName;
    @end
    

    代码中先定义一个代理MoveCollectionViewCellDelegate,代理中需要实现是cell的长按与拖动手势,其中拖动手势只需要在iOS 9之前的系统中添加。
    再添加了一个cellName的属性,待会来重写set方法
    到.m文件中

    //
    //  MoveCollectionViewCell.m
    //  MJChangeItem
    //
    //  Created by 马家俊 on 16/12/12.
    //  Copyright © 2016年 MJJ. All rights reserved.
    //
    
    #import "MoveCollectionViewCell.h"
    
    @interface MoveCollectionViewCell()<UIGestureRecognizerDelegate>
    @property(nonatomic,strong) UILabel* nameLab;
    @end
    @implementation MoveCollectionViewCell
    @synthesize p_MoveCollectionViewCellDelegate = m_MoveCollectionViewCellDelegate;
    @synthesize nameLab;
    - (instancetype)initWithFrame:(CGRect)frame
    {
        self = [super initWithFrame:frame];
        if (self) {
            [self addGestureCell];
            [self addLab];
        }
        return self;
    }
    

    这段是定义个label,添加下delegate,初始化下cell,没啥好说的。
    实现下init中的两个方法

    //为cell添加手势
    -(void)addGestureCell
    {
        UILongPressGestureRecognizer * longPress =[[UILongPressGestureRecognizer alloc]initWithTarget:self action:@selector(GesturePress:)];
        longPress.delegate = self;
        [self addGestureRecognizer:longPress];
        if ([[[UIDevice currentDevice] systemVersion] floatValue] <9)
        {
            UIPanGestureRecognizer * panGes =[[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(GesturePress:)];
            panGes.delegate = self;
            [self addGestureRecognizer:panGes];
        }
    }
    //为cell添加lab
    -(void)addLab
    {
        nameLab = [UILabel new];
        nameLab.font = [UIFont systemFontOfSize:12];
        nameLab.textColor = [UIColor grayColor];
        nameLab.layer.borderColor = [UIColor grayColor].CGColor;
        nameLab.layer.borderWidth = 1;
        nameLab.layer.cornerRadius = 5;
        nameLab.layer.masksToBounds = YES;
        nameLab.textAlignment = NSTextAlignmentCenter;
        [self addSubview:nameLab];
    }
    

    最后重写下set方法

    -(void)setCellName:(NSString *)cellName
    {
        _cellName = cellName;
        nameLab.text = cellName;
        nameLab.frame = CGRectMake(0, 0, self.frame.size.width - 5, self.frame.size.height - 5);
        nameLab.center = CGPointMake(self.frame.size.width / 2, self.frame.size.height / 2);
    }
    

    哦,还有手势对应的方法,代理跳转到vc中实现

    - (void)GesturePress:(UIGestureRecognizer *)gestureRecognizer{
        
        if (m_MoveCollectionViewCellDelegate && [m_MoveCollectionViewCellDelegate respondsToSelector:@selector(GesturePressDelegate:)]) {
            [m_MoveCollectionViewCellDelegate GesturePressDelegate:gestureRecognizer];
        }
    }
    

    这是cell的全部代码。。。。

    接下来去vc中

    所有vc中声明的属性

    //
    //  ViewController.m
    //  MJChangeItem
    //
    //  Created by 马家俊 on 16/12/12.
    //  Copyright © 2016年 MJJ. All rights reserved.
    //
    
    #import "ViewController.h"
    #import "MoveCollectionViewCell.h"
    #define K_MAIN_SCREEN_WIDTH [UIScreen mainScreen].bounds.size.width
    
    #define K_MAIN_SCREEN_HEIGHT [UIScreen mainScreen].bounds.size.height
    
    @interface ViewController ()<UICollectionViewDelegate,UICollectionViewDataSource,MoveCollectionViewCellDelegate>
    @property(nonatomic,strong) UICollectionView* MJColloctionView;
    @property(nonatomic,strong) NSMutableArray* arr;
    //iOS9 及之后弃用以下属性
    @property(nonatomic,strong) UIView * shotView;
    @property(nonatomic,strong) NSIndexPath * indexPath;
    @property(nonatomic,strong) NSIndexPath * nextIndexPath;
    @property(nonatomic,weak) MoveCollectionViewCell * originalCell;
    @end
    

    懒加载初始化个UICollectionView

    #define kItemSpace      20
    
    - (UICollectionView *)MJColloctionView
    {
        if (!MJColloctionView) {
            UICollectionViewFlowLayout * layout = [[UICollectionViewFlowLayout alloc] init];
            layout.itemSize = CGSizeMake((K_MAIN_SCREEN_WIDTH-(kItemSpace*8))/9, 30);
            MJColloctionView = [[UICollectionView alloc]initWithFrame:CGRectMake(0, 44, K_MAIN_SCREEN_WIDTH, K_MAIN_SCREEN_HEIGHT-44) collectionViewLayout:layout];
            [MJColloctionView registerClass:[MoveCollectionViewCell class] forCellWithReuseIdentifier:@"MoveCollectionViewCell"];
            MJColloctionView.dataSource = self;
            MJColloctionView.delegate = self;
            MJColloctionView.backgroundColor = [UIColor whiteColor];
        }
        return MJColloctionView;
    }
    

    是线下UIColloction代理

    - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
        return _arr.count;
    }
    
    - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
        
        MoveCollectionViewCell * cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"MoveCollectionViewCell" forIndexPath:indexPath];
        
        cell.p_MoveCollectionViewCellDelegate = self;
        cell.cellName = [_arr objectAtIndex:indexPath.row];
        return cell;
    }
    -(BOOL)collectionView:(UICollectionView *)collectionView canMoveItemAtIndexPath:(NSIndexPath *)indexPath
    {
        return YES;
    }
    
    - (void)collectionView:(UICollectionView *)collectionView moveItemAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath*)destinationIndexPath {
        id objc = [_arr objectAtIndex:sourceIndexPath.item];
        [_arr removeObject:objc];
        [_arr insertObject:objc atIndex:destinationIndexPath.item];
    }
    

    这样至少能够显示出来colloctionview了;
    最后要实现的就是拖曳这一个动作了

    -(void)GesturePressDelegate:(UIGestureRecognizer *)gestureRecognizer
    {
        if ([[[UIDevice currentDevice] systemVersion] floatValue] >9) {
            switch (gestureRecognizer.state) {
                case UIGestureRecognizerStateBegan:{
                    //判断手势落点位置是否在路径上
                    NSIndexPath *indexPath = [MJColloctionView indexPathForItemAtPoint:[gestureRecognizer locationInView:self.MJColloctionView]];
                    if (indexPath == nil) {
                        break;
                    }
                    //在路径上则开始移动该路径上的cell
                    [MJColloctionView beginInteractiveMovementForItemAtIndexPath:indexPath];
                }
                    break;
                case UIGestureRecognizerStateChanged:
                    //移动过程当中随时更新cell位置
                    [MJColloctionView updateInteractiveMovementTargetPosition:[gestureRecognizer locationInView:self.MJColloctionView]];
                    break;
                case UIGestureRecognizerStateEnded:
                    //移动结束后关闭cell移动
                    [MJColloctionView endInteractiveMovement];
                    break;
                default:
                    [MJColloctionView cancelInteractiveMovement];
                    break;
            }
    
        }else
        {
            MoveCollectionViewCell* cell = (MoveCollectionViewCell*)gestureRecognizer.view;
            static CGPoint startPoint;
            if (gestureRecognizer.state == UIGestureRecognizerStateBegan) {
                _shotView = [cell snapshotViewAfterScreenUpdates:NO];
                _shotView.center = cell.center;
                
                NSLog(@"%@",cell.description);
                NSLog(@"%@",_shotView.description);
                [MJColloctionView addSubview:_shotView];
                _indexPath = [MJColloctionView indexPathForCell:cell];
                _originalCell = cell;
                _originalCell.hidden = YES;
                startPoint = [gestureRecognizer locationInView:MJColloctionView];
            }else if (gestureRecognizer.state == UIGestureRecognizerStateChanged)
            {
                //获取移动量
                CGFloat tranX = [gestureRecognizer locationOfTouch:0 inView:MJColloctionView].x - startPoint.x;
                CGFloat tranY = [gestureRecognizer locationOfTouch:0 inView:MJColloctionView].y - startPoint.y;
                
                //进行移动
                _shotView.center = CGPointApplyAffineTransform(_shotView.center, CGAffineTransformMakeTranslation(tranX, tranY));
                //更新初始位置
                startPoint = [gestureRecognizer locationOfTouch:0 inView:MJColloctionView];
                for (UICollectionViewCell *cellVisible in [MJColloctionView visibleCells])
                {
                    //移动的截图与目标cell的center直线距离
                    CGFloat space = sqrtf(pow(_shotView.center.x - cellVisible.center.x, 2) + powf(_shotView.center.y - cellVisible.center.y, 2));
                    //判断是否替换位置,通过直接距离与重合程度
                    if (space <= _shotView.frame.size.width/2&&(fabs(_shotView.center.y-cellVisible.center.y) <= _shotView.bounds.size.height/2)) {
                        _nextIndexPath = [MJColloctionView indexPathForCell:cellVisible];
                        if (_nextIndexPath.item > _indexPath.item)
                        {
                            for(NSInteger i = _indexPath.item; i <_nextIndexPath.item;i++)
                            {
                                //移动数据源位置
                                [_arr exchangeObjectAtIndex:i withObjectAtIndex:i+1];
                            }
                        }else
                        {
                            for(NSInteger i = _indexPath.item; i <_nextIndexPath.item;i--)
                            {
                                //移动数据源位置
                                [_arr exchangeObjectAtIndex:i withObjectAtIndex:i-1];
                            }
                        }
                        //移动视图cell位置
                        [MJColloctionView moveItemAtIndexPath:_indexPath toIndexPath:_nextIndexPath];
                        //更新移动视图的数据
                        _indexPath = _nextIndexPath;
                        break;
                    }
                }
            }else if (gestureRecognizer.state == UIGestureRecognizerStateEnded)
            {
                [_shotView removeFromSuperview];
                [_originalCell setHidden:NO];
            }
    
        }
    }
    

    viewDidLoad加下数据

    - (void)viewDidLoad {
        [super viewDidLoad];
        _arr = [[NSMutableArray alloc]initWithArray:[NSArray arrayWithObjects:@"我",@"的",@"背",@"脊",@"如",@"荒",@"丘",@",",@"而",@"你",@"却",@"微",@"笑",@"摆",@"手",@",",@"把",@"它",@"当",@"成",@"整",@"个",@"宇",@"宙", nil]];
        [self.view addSubview:self.MJColloctionView];
        // Do any additional setup after loading the view, typically from a nib.
    }
    
    2016-12-14 10_44_44.gif

    就酱..................QAQ

    相关文章

      网友评论

        本文标题:iOS 拖拽排序实现

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