iOS 拖拽排序实现

老早之前说要做这个,主要是看了微博的一个转发,然后发现其实系统已经有自带的功能了。不管怎么样,先写一下基于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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350

推荐阅读更多精彩内容