日常小知识点iOS开发

iOS 拖拽排序实现

2016-11-25  本文已影响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

上一篇下一篇

猜你喜欢

热点阅读