iOS代码段

73 阅读6分钟

//

//  OCFTFreeCombinationView.m

//  ZNSLSDK

//

//  Copyright © 2022 yull. All rights reserved.

//

#import "OCFTFreeCombinationView.h"

#import "Masonry.h"

#import "OCFTMultiRecordDefine.h"

#import "OCFTFreeCombinationCollectionViewCell.h"

#import "PAFFToast.h"

#import "OCFTUICollectionViewLeftAlignedFlowLayout.h"

#import "OCFTFreeCombinationDataModel.h"

#import "ZNSLLogTool.h"

#define OCFTItemWidth 115.f

static NSString * const cellIndentifier = @"cellIndentifier";

@interface OCFTFreeCombinationView()<UICollectionViewDataSource,UICollectionViewDelegate,UIGestureRecognizerDelegate,OCFTUICollectionViewDelegateLeftAlignedFlowLayout>

@property (nonatomic, strong) UICollectionView *freeCollectionView;

@property (nonatomic, strong) NSArray *dataSourceArray;

@property (nonatomic, strong) NSMutableArray *dataMutableArray;

@property (nonatomic, strong) UIPanGestureRecognizer *panGesture;

@property (nonatomic, strong) NSIndexPath *activeIndexPath;

//拖动的cell

@property (nonatomic, strong) OCFTFreeCombinationCollectionViewCell *activeCell;

@property (nonatomic, strong) NSIndexPath *changedIndexPath;

@property (nonatomic, assign) CGPoint changedPoint;

@property (nonatomic, copy) void(^completedBlock)(NSString *groupString);

@property (nonatomic, assign) NSUInteger roleCount;

@property (nonatomic, strong) UICollectionSectionColorReusableView *sectionColorReusableView;

//记录相交的Cell

@property (nonatomic, strong) OCFTFreeCombinationCollectionViewCell *intersectCell;

@end

@implementation OCFTFreeCombinationView

#pragma mark - init

  • (instancetype)initWithDataSourceArray:(NSArray *)datSourceArray completedBlock:(void(^)(NSString *groupString))completedBlock {

    if (self = [super init]) {

        self.roleCount = datSourceArray.count;

        self.completedBlock = completedBlock;

        self.intersectCell = nil;

        [self handleDataSource:datSourceArray];

        [self addAllSubView];

    }

    return self;

}

  • (void)handleDataSource:(NSArray *)array {

    self.dataMutableArray = [NSMutableArray array];

    for (NSInteger i = 0;i < array.count; i ++) {

        NSMutableArray *tempArray = [NSMutableArray array];

        OCFTFreeCombinationDataModel *model = [[OCFTFreeCombinationDataModel alloc]init];

        if (0 == i) {

            model.nailShow = YES;

        }else{

            model.nailShow = NO;

        }

        NSDictionary *dict = array[i];

        if ([dict[@"role"] isEqualToString:@"1"]) {

            model.name = @"代理人";

        }else if ([dict[@"role"] isEqualToString:@"2"]){

            model.name = @"投保人";

        }else if ([dict[@"role"] isEqualToString:@"4"]){

            model.name = @"被保人二";

        }else if([dict[@"role"] isEqualToString:@"3"]){

            //是否包含被保人二

            if ([self getHasContainerInsured:array]) {

                model.name = @"被保人一";

            }else{

                model.name = @"被保人";

            }

        }else{

            model.name = @"未知角色";

        }

        model.excuteRoleShow = YES;

        [tempArray addObject:model];

        [self.dataMutableArray addObject:tempArray];

    }

    self.dataSourceArray = [NSArray arrayWithArray:self.dataMutableArray];

}

  • (BOOL)getHasContainerInsured:(NSArray *)array {

    BOOL isContainer = NO;

    for (NSInteger i = 0; i < array.count; i ++) {

        NSDictionary *dict = array[i];

        if ([dict[@"role"] isEqualToString:@"4"]) {

            isContainer = YES;

            break;

        }

    }

    return isContainer;

}

  • (void)addAllSubView {

    UIView *topView = [UIView new];

    topView.backgroundColor = UIColorFromHex(0xFFF1F3);

    topView.layer.masksToBounds = YES;

    topView.layer.cornerRadius = 4.f;

    topView.layer.borderColor = UIColorFromHex(0xFFC2C5).CGColor;

    topView.layer.borderWidth = 1.f;

    [self addSubview:topView];

    [topView mas_makeConstraints:^(MASConstraintMaker *make) {

        make.left.mas_equalTo(self).offset(16.f);

        make.right.mas_equalTo(self).offset(-16.f);

        make.top.mas_equalTo(self).offset(11.f);

        make.height.mas_equalTo(60.f);

    }];

    

    UILabel *warningLabel = [[UILabel alloc]init];

    warningLabel.text = @"!";

    warningLabel.backgroundColor = [UIColor colorWithRed:248/255.f green:205/255.f blue:118/255.f alpha:1.f];

    warningLabel.font = [UIFont systemFontOfSize:12.f];

    warningLabel.textColor = [UIColor whiteColor];

    warningLabel.textAlignment = NSTextAlignmentCenter;

    warningLabel.layer.masksToBounds = YES;

    warningLabel.layer.cornerRadius = 7.5f;

    [topView addSubview:warningLabel];

    [warningLabel mas_makeConstraints:^(MASConstraintMaker *make) {

        make.left.mas_equalTo(topView).offset(16.f);

        make.top.mas_equalTo(topView).offset(9.f);

        make.size.mas_equalTo(CGSizeMake(15.f, 15.f));

    }];

    

    UITextView *textView = [[UITextView alloc]init];

    textView.backgroundColor = [UIColor clearColor];

    textView.text = @"除代理人外,其他角色可拖动自由组合。\n请确认好各组人员在哪一端进行录制。(默认是通过第一位的金管家进行录制)";

    textView.font = [UIFont systemFontOfSize:12.f];

    textView.textColor = UIColorFromHex(0x3F4254);

    textView.textAlignment = NSTextAlignmentLeft;

    textView.userInteractionEnabled = NO;

    [topView addSubview:textView];

    [textView mas_makeConstraints:^(MASConstraintMaker *make) {

        make.left.mas_equalTo(warningLabel.mas_right).offset(8.f);

        make.right.mas_equalTo(topView).offset(-16.f);

        make.top.bottom.mas_equalTo(topView);

    }];

    

    //表视图

    [self addSubview:self.freeCollectionView];

    [self.freeCollectionView mas_makeConstraints:^(MASConstraintMaker *make) {

        make.left.mas_equalTo(self).offset(16.f);

        make.right.mas_equalTo(self).offset(-16.f);

        make.top.mas_equalTo(topView.mas_bottom).offset(16.f);

        make.height.mas_equalTo(62 * self.dataSourceArray.count);

    }];

    [self.freeCollectionView reloadData];

    //添加拖动手势

    self.panGesture = [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(panGestureMoving:)];

    self.panGesture.delegate = self;

    [self.freeCollectionView addGestureRecognizer:self.panGesture];

    

    //回传数据

    if (self.completedBlock) {

        self.completedBlock([self getGroupString]);

    }

}

  • (NSString *)getGroupString {

    NSString *jsonStr = @"";

    for (NSInteger i = 0; i < self.dataSourceArray.count; i ++) {

        NSArray *tempArray = self.dataSourceArray[i];

        if ((i != 0) && (tempArray.count > 0)) {

            jsonStr =  [jsonStr stringByAppendingString:@"&"];

        }

        

        for (NSInteger j = 0; j < tempArray.count ; j ++) {

            OCFTFreeCombinationDataModel *model = tempArray[j];

            if (0 == j) {

                if ([model.name isEqualToString:@"代理人"]) {

                    jsonStr =  [jsonStr stringByAppendingString:@"1"];

                }else if([model.name isEqualToString:@"投保人"]){

                    jsonStr = [jsonStr stringByAppendingString:@"2"];

                }else if([model.name isEqualToString:@"被保人"] || [model.name isEqualToString:@"被保人一"]){

                    jsonStr = [jsonStr stringByAppendingString:@"3"];

                }else if([model.name isEqualToString:@"被保人二"]){

                    jsonStr = [jsonStr stringByAppendingString:@"4"];

                }else{

                    

                }

            }else{

                if ([model.name isEqualToString:@"代理人"]) {

                    jsonStr =  [jsonStr stringByAppendingString:@"/1"];

                }else if([model.name isEqualToString:@"投保人"]){

                    jsonStr = [jsonStr stringByAppendingString:@"/2"];

                }else if([model.name isEqualToString:@"被保人"] || [model.name isEqualToString:@"被保人一"]){

                    jsonStr = [jsonStr stringByAppendingString:@"/3"];

                }else if([model.name isEqualToString:@"被保人二"]){

                    jsonStr = [jsonStr stringByAppendingString:@"/4"];

                }else{

                    

                }

            }

        }

    }

    [ZNSLLogTool logWithLevel:ZNSLLocalLogLevelInfo type:ZNSLLocalLogType_AUDIO_VIDEO content:[NSString stringWithFormat:@"自由组合结果ABC==:%@",jsonStr]];

    return jsonStr;

}

#pragma mark - Guesture

//是否允许开始触发手势

  • (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)panGesture;

{

    self.activeIndexPath = [self.freeCollectionView indexPathForItemAtPoint:[panGesture locationInView:self.freeCollectionView]];

    if (nil == self.activeIndexPath)

    {

        [ZNSLLogTool logWithLevel:ZNSLLocalLogLevelInfo type:ZNSLLocalLogType_AUDIO_VIDEO content:@"ABC==:self.activeIndexPath=nil"];

        //取消手势

        return NO;

    }

    return YES;

}

  • (void)panGestureMoving:(UIPanGestureRecognizer *)panGesture {

    switch (panGesture.state) {

        case UIGestureRecognizerStateBegan:{

            [ZNSLLogTool logWithLevel:ZNSLLocalLogLevelInfo type:ZNSLLocalLogType_AUDIO_VIDEO content:@"ABC==:StateBegan"];

            self.activeIndexPath = [self.freeCollectionView indexPathForItemAtPoint:[panGesture locationInView:self.freeCollectionView]];

            if (nil == self.activeIndexPath) {

                [ZNSLLogTool logWithLevel:ZNSLLocalLogLevelInfo type:ZNSLLocalLogType_AUDIO_VIDEO content:@"ABC==:StateBegan self.activeIndexPath = nil"];

                break;

            }

            OCFTFreeCombinationCollectionViewCell *cell = (OCFTFreeCombinationCollectionViewCell *)[self.freeCollectionView cellForItemAtIndexPath:self.activeIndexPath];

            self.activeCell = cell;

            if ((nil != self.activeIndexPath) && (0 == self.activeIndexPath.section)) {

                [PAFFToast showToast:@"除代理人外,其他角色可拖动" duration:2.0f];

                self.activeCell.isFixed = YES;

            }else{

                self.activeCell.isMoving = YES;

                //隐藏拖动section的DecorationView

                NSArray *array = [self  getDecorationView];

                for (NSInteger i = 0; i < array.count; i ++) {

                    UICollectionSectionColorReusableView *tempView = array[i];

                    NSArray *array = self.dataMutableArray[self.activeIndexPath.section];

                    if (1 == array.count && ((tempView.tag - 10000) == self.activeIndexPath.section)) {

                        self.sectionColorReusableView = tempView;

                        self.sectionColorReusableView.hidden = YES;

                    }else{

                        tempView.hidden = NO;

                    }

                }

            }

            [self.freeCollectionView beginInteractiveMovementForItemAtIndexPath:self.activeIndexPath];

           break;

        }

        case UIGestureRecognizerStateChanged:{

            [ZNSLLogTool logWithLevel:ZNSLLocalLogLevelInfo type:ZNSLLocalLogType_AUDIO_VIDEO content:@"ABC==:StateChanged"];

            if (nil == self.activeIndexPath) {

                [ZNSLLogTool logWithLevel:ZNSLLocalLogLevelInfo type:ZNSLLocalLogType_AUDIO_VIDEO content:@"ABC==:StateChanged self.activeIndexPath = nil"];

                break;

            }

            if (0 == self.activeIndexPath.section) {//代理人不可以拖动

                [ZNSLLogTool logWithLevel:ZNSLLocalLogLevelInfo type:ZNSLLocalLogType_AUDIO_VIDEO content:@"ABC==:StateChanged代理人不可以拖动"];

                break;

            }

            //当前手指位置

            self.changedPoint = [panGesture locationInView:self.freeCollectionView];

            self.changedIndexPath = [self.freeCollectionView indexPathForItemAtPoint:self.changedPoint];

            //超过边界处理

            if ((self.changedPoint.x <= 0.f) || (self.changedPoint.y <= 0.f) || (self.changedPoint.x >= self.freeCollectionView.bounds.size.width) || (self.changedPoint.y >= self.freeCollectionView.bounds.size.height)) {

                [ZNSLLogTool logWithLevel:ZNSLLocalLogLevelInfo type:ZNSLLocalLogType_AUDIO_VIDEO content:@"ABC==:超过边界"];

            }else{

                //没有超过边界,处理相交

                [self handleIntersect];

                //更新拖动位置

                [self.freeCollectionView updateInteractiveMovementTargetPosition:self.changedPoint];

            }

            break;

        }

        case UIGestureRecognizerStateEnded:{

            [ZNSLLogTool logWithLevel:ZNSLLocalLogLevelInfo type:ZNSLLocalLogType_AUDIO_VIDEO content:@"ABC==:StateEnded"];

            if (nil == self.activeIndexPath) {

                [self.freeCollectionView cancelInteractiveMovement];

                [ZNSLLogTool logWithLevel:ZNSLLocalLogLevelInfo type:ZNSLLocalLogType_AUDIO_VIDEO content:@"ABC==:StateEnded self.activeIndexPath = nil"];

                break;

            }

            //取消移动

            [self.freeCollectionView cancelInteractiveMovement];

            //代理人固定样式和cell移动样式

            if (0 == self.activeIndexPath.section) {

                [ZNSLLogTool logWithLevel:ZNSLLocalLogLevelInfo type:ZNSLLocalLogType_AUDIO_VIDEO content:@"ABC==:StateEnded代理人不可以拖动"];

                self.activeCell.isFixed = NO;

                self.intersectCell = nil;

            }else{

                self.activeCell.isMoving = NO;

                [self delayOneSecondShow];//延迟0.15s显示DecorationView

                

                if (nil == self.intersectCell) {//没有相交

                   [ZNSLLogTool logWithLevel:ZNSLLocalLogLevelInfo type:ZNSLLocalLogType_AUDIO_VIDEO content:@"ABC==:StateEnded没有相交"];

                   [self handleNoInterest];

                }else{//相交

                    [ZNSLLogTool logWithLevel:ZNSLLocalLogLevelInfo type:ZNSLLocalLogType_AUDIO_VIDEO content:@"ABC==:StateEnded有相交过"];

                   

                    if (!self.intersectCell.isIntersect) {//相交过,但最后手势结束点没有相交

                        [ZNSLLogTool logWithLevel:ZNSLLocalLogLevelInfo type:ZNSLLocalLogType_AUDIO_VIDEO content:@"ABC==:StateEnded最后结束点没有相交"];

                        [self handleNoInterest];

                        self.intersectCell = nil;

                    }else{

                        [ZNSLLogTool logWithLevel:ZNSLLocalLogLevelInfo type:ZNSLLocalLogType_AUDIO_VIDEO content:@"ABC==:StateEnded最后结束点相交"];

                        //处理是否和代理人相交且拖动的不是代理人

                        NSIndexPath *empIndexPath = [NSIndexPath indexPathForRow:0 inSection:0];

                        if (empIndexPath == [self.freeCollectionView indexPathForCell:self.intersectCell] && self.intersectCell.isIntersect){

                            self.intersectCell.isIntersect = NO;

                            self.intersectCell = nil;

                            if (!(0 == self.activeIndexPath.section)) {

                                [PAFFToast showToast:@"代理人不能和其他角色合并" duration:2.0f];

                            }

                            [ZNSLLogTool logWithLevel:ZNSLLocalLogLevelInfo type:ZNSLLocalLogType_AUDIO_VIDEO content:@"ABC==:StateEnded代理人不能和其他角色合并"];

                        }else if(0 == self.activeIndexPath.section){

                            self.activeCell.isFixed = NO;

                            self.intersectCell = nil;

                            [PAFFToast showToast:@"除代理人外,其他角色可拖动" duration:2.0f];

                            [ZNSLLogTool logWithLevel:ZNSLLocalLogLevelInfo type:ZNSLLocalLogType_AUDIO_VIDEO content:@"ABC==:StateEnded除代理人外,其他角色可拖动"];

                        }else{

                            NSIndexPath *sourceIndexPath = self.activeIndexPath;

                            NSIndexPath *destinationIndexPath = [self.freeCollectionView indexPathForCell:self.intersectCell];

                            if ((sourceIndexPath.section == destinationIndexPath.section) && (sourceIndexPath.row == destinationIndexPath.row)) {

                                [ZNSLLogTool logWithLevel:ZNSLLocalLogLevelInfo type:ZNSLLocalLogType_AUDIO_VIDEO content:@"ABC==:StateEnded和自己相交还原到自己的位置"];

                                //重置相交的cell

                                self.intersectCell.isIntersect = NO;

                                self.intersectCell = nil;

                                break;

                            }

                            if (self.changedPoint.x < self.intersectCell.center.x ) {//插入到头部

                                [self freeCombinationMoveItemAtIndexPath:sourceIndexPath toIndexPath:destinationIndexPath destinationFront:YES];

                            }else{//插入到尾部

                                [self freeCombinationMoveItemAtIndexPath:sourceIndexPath toIndexPath:destinationIndexPath destinationFront:NO];

                            }

                           

                            dispatch_async(dispatch_get_main_queue(), ^{

                                //重置相交的cell

                                self.intersectCell.isIntersect = NO;

                                self.intersectCell = nil;

                               

                                self.dataSourceArray = [self.dataMutableArray copy];

                                [self.freeCollectionView reloadData];

                                //回传数据

                                if (self.completedBlock) {

                                    self.completedBlock([self getGroupString]);

                                }

                            });

                       }

                    }

                }

            }

            break;

        }

        default:{

            [ZNSLLogTool logWithLevel:ZNSLLocalLogLevelInfo type:ZNSLLocalLogType_AUDIO_VIDEO content:@"ABC==:default"];

            [self.freeCollectionView cancelInteractiveMovement];

            [self delayOneSecondShow];

            break;

        }

    }

}

#pragma mark - private method

  • (void)delayOneSecondShow {

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.11f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{

        self.sectionColorReusableView.hidden = NO;

    });

}

//没有相交

  • (void)handleNoInterest {

    if (nil == self.changedIndexPath) {//拖动到空白处

         if (self.changedPoint.y >= [self getCollectionViewLastEmptyPointY]) {//往底部拖动

             NSMutableArray *mutableArray = [NSMutableArray arrayWithArray:self.dataMutableArray[self.activeIndexPath.section]];

             if ((mutableArray.count > 1) && (self.activeIndexPath != nil)) {//重新单独拖动为一组,拖动的那组count大于1

                 [self handleSeparateGroup:mutableArray];

             }else{

                 [ZNSLLogTool logWithLevel:ZNSLLocalLogLevelInfo type:ZNSLLocalLogType_AUDIO_VIDEO content:@"ABC==:拖动超过下边界,不能单独成组"];

             }

         }else{

             [ZNSLLogTool logWithLevel:ZNSLLocalLogLevelInfo type:ZNSLLocalLogType_AUDIO_VIDEO content:@"ABC==:拖动超过顶左右边界"];

         }

    }else{

        if (self.activeIndexPath == self.changedIndexPath) {

            [ZNSLLogTool logWithLevel:ZNSLLocalLogLevelInfo type:ZNSLLocalLogType_AUDIO_VIDEO content:@"ABC==:handleNoInterest自己相交"];

        }else{

            [ZNSLLogTool logWithLevel:ZNSLLocalLogLevelInfo type:ZNSLLocalLogType_AUDIO_VIDEO content:@"ABC==:异常情况,不存在"];

            NSString *stringContent = [NSString stringWithFormat:@"ABC==self.activeIndexPath:%ld-%ld,self.changedIndexPath:%ld-%ld",self.activeIndexPath.section,self.activeIndexPath.row,self.changedIndexPath.section,self.changedIndexPath.row];

            [ZNSLLogTool logWithLevel:ZNSLLocalLogLevelInfo type:ZNSLLocalLogType_AUDIO_VIDEO content:stringContent];

        }

    }

}

//单独成组

  • (void)handleSeparateGroup:(NSMutableArray *)mutableArray {

    [ZNSLLogTool logWithLevel:ZNSLLocalLogLevelInfo type:ZNSLLocalLogType_AUDIO_VIDEO content:@"ABC==:拖动超过下边界,可以单独成组"];

    

    if (0 == self.activeIndexPath.row) {//移除头部

        OCFTFreeCombinationDataModel *nextModel = mutableArray[self.activeIndexPath.row + 1];

        nextModel.excuteRoleShow = YES;

    }

    

    [ZNSLLogTool logWithLevel:ZNSLLocalLogLevelInfo type:ZNSLLocalLogType_AUDIO_VIDEO content:@"ABC==:removeObject"];

        

    OCFTFreeCombinationDataModel *model = mutableArray[self.activeIndexPath.row];

    [mutableArray removeObjectAtIndex:self.activeIndexPath.row];

    [self.dataMutableArray replaceObjectAtIndex:self.activeIndexPath.section withObject:[mutableArray copy]];

        

    [ZNSLLogTool logWithLevel:ZNSLLocalLogLevelInfo type:ZNSLLocalLogType_AUDIO_VIDEO content:@"ABC==:replaceObjectAtIndex"];

    //数据移动处理

    [self handleDataMove];

    

    [ZNSLLogTool logWithLevel:ZNSLLocalLogLevelInfo type:ZNSLLocalLogType_AUDIO_VIDEO content:@"ABC==:handleDataMove"];

        

    //获取空数组的下标

    NSInteger index = [self getEmptyArrayWithIndex];

    NSMutableArray *lastMutableArray = [NSMutableArray arrayWithArray:self.dataMutableArray[index]];

    model.excuteRoleShow = YES;

    [lastMutableArray addObject:model];

    [self.dataMutableArray replaceObjectAtIndex:index withObject:[lastMutableArray copy]];

        

    dispatch_async(dispatch_get_main_queue(), ^{

        self.dataSourceArray = [self.dataMutableArray copy];

        [self.freeCollectionView reloadData];

        [ZNSLLogTool logWithLevel:ZNSLLocalLogLevelInfo type:ZNSLLocalLogType_AUDIO_VIDEO content:@"ABC==:reloadData之后"];

        //回传数据

        if (self.completedBlock) {

            self.completedBlock([self getGroupString]);

        }

    });

}

//处理相交

  • (void)handleIntersect {

    for (OCFTFreeCombinationCollectionViewCell *cell in self.freeCollectionView.visibleCells) {

        if ([self.freeCollectionView indexPathForCell:cell] == self.activeIndexPath) {

            continue;

        }

        CGRect rect1 = CGRectMake(fabs(self.changedPoint.x - cell.bounds.size.width/2), fabs(self.changedPoint.y - cell.bounds.size.height/2), cell.bounds.size.width, cell.bounds.size.height);

        CGRect rect2 = cell.frame;

        if (CGRectIntersectsRect(rect1, rect2)) {//相交

            OCFTFreeCombinationCollectionViewCell *lastCell = [self getClosestDistanceCell];//获取最近相交的cell

            if ([self.freeCollectionView indexPathForCell:cell] == [self.freeCollectionView indexPathForCell:lastCell]) {

                [ZNSLLogTool logWithLevel:ZNSLLocalLogLevelInfo type:ZNSLLocalLogType_AUDIO_VIDEO content:@"ABC==:相交changed"];

                cell.isIntersect = YES;

                self.intersectCell = cell;

            }else{

                cell.isIntersect = NO;

                [ZNSLLogTool logWithLevel:ZNSLLocalLogLevelInfo type:ZNSLLocalLogType_AUDIO_VIDEO content:@"ABC==:不相交changed1"];

            }

        }else{

            cell.isIntersect = NO;

            [ZNSLLogTool logWithLevel:ZNSLLocalLogLevelInfo type:ZNSLLocalLogType_AUDIO_VIDEO content:@"ABC==:不相交changed2"];

        }

    }

}

//获取相交的数组

  • (NSArray *)getIntersectCellWithArray {

    NSMutableArray *mutableArray = [NSMutableArray array];

    for (OCFTFreeCombinationCollectionViewCell *cell in self.freeCollectionView.visibleCells) {

        if ([self.freeCollectionView indexPathForCell:cell] == self.activeIndexPath) {

            continue;

        }

        CGRect rect1 = CGRectMake(fabs(self.changedPoint.x - cell.bounds.size.width/2), fabs(self.changedPoint.y - cell.bounds.size.height/2), cell.bounds.size.width, cell.bounds.size.height);

        CGRect rect2 = cell.frame;

        if (CGRectIntersectsRect(rect1, rect2)) {//相交

            [mutableArray addObject:cell];

        }

    }

    return [mutableArray copy];

}

//获取相交最近的Cell

  • (OCFTFreeCombinationCollectionViewCell *)getClosestDistanceCell {

    NSArray *array = [self getIntersectCellWithArray];

    if (0 == array.count) {

       return nil;

    }else if (1 == array.count){

        OCFTFreeCombinationCollectionViewCell *cell = [array firstObject];

        return cell;

    }else{

        NSMutableArray *tempArray = [NSMutableArray array];

        for (NSInteger i = 0; i < array.count; i ++) {

            OCFTFreeCombinationCollectionViewCell *cell = array[i];

            CGFloat space = sqrtf(pow(self.changedPoint.x - cell.center.x, 2) + powf(self.changedPoint.y - cell.center.y, 2));

            [tempArray addObject:[NSNumber numberWithFloat:space]];

        }

        //查找出最小距离

        CGFloat minSpace = 0.f;

        for (NSInteger j = 0; j < tempArray.count; j ++) {

            NSNumber *number = tempArray[j];

            if (0 == j) {

                minSpace = [number floatValue];

            }else{

                if (minSpace > [number floatValue]) {

                    minSpace = [number floatValue];

                }

            }

        }

        NSInteger index = [tempArray indexOfObject:[NSNumber numberWithFloat:minSpace]];

        OCFTFreeCombinationCollectionViewCell *cell1 = array[index];

        return cell1;

    }

}

  • (CGFloat)getCollectionViewLastEmptyPointY {

    NSInteger index = 0;

    for (NSInteger k = self.dataMutableArray.count - 1;k >= 0; k --) {

        NSArray *array = self.dataMutableArray[k];

        if (array.count > 0) {

            index ++;

        }

    }

    CGFloat pointY = index * 16 + index * 44.f - 8.f;

    return pointY;

}

  • (NSInteger)getEmptyArrayWithIndex {

    NSInteger index = 0;

    for (NSInteger k = 0; k < self.dataMutableArray.count; k ++) {

        NSArray *array = self.dataMutableArray[k];

        if (array.count == 0) {

            index = k;

            break;

        }

    }

    return index;

}

  • (void)handleDataMove {

    for (NSInteger i = 0; i < self.dataMutableArray.count; i ++) {

        NSArray *array = self.dataMutableArray[i];

        if (0 == array.count) {

            [self.dataMutableArray removeObject:array];

        }

    }

    

    for (NSInteger j = 0; j < (self.roleCount - self.dataMutableArray.count); j ++) {

        [self.dataMutableArray addObject:[NSArray array]];

    }

}

  • (void)freeCombinationMoveItemAtIndexPath:(NSIndexPath )sourceIndexPath toIndexPath:(NSIndexPath)destinationIndexPath  destinationFront:(BOOL)destinationFront {

    if (destinationIndexPath.section == sourceIndexPath.section) {//同一个section移动

        [ZNSLLogTool logWithLevel:ZNSLLocalLogLevelInfo type:ZNSLLocalLogType_AUDIO_VIDEO content:@"ABC==:同一个section移动"];

        NSArray *sameSectionArray = [NSArray arrayWithArray:self.dataMutableArray[destinationIndexPath.section]];

        BOOL canChange = (sameSectionArray.count > sourceIndexPath.item) && (sameSectionArray.count > destinationIndexPath.item);

        if (destinationFront) {//插入到destinationIndexPath的头部

            if (canChange) {

                if (sourceIndexPath == [NSIndexPath indexPathForRow:(destinationIndexPath.row - 1) inSection:destinationIndexPath.section]) {

                   [ZNSLLogTool logWithLevel:ZNSLLocalLogLevelInfo type:ZNSLLocalLogType_AUDIO_VIDEO content:@"ABC==:头部,移动到原来的位置不用处理"];

                }else{

                   [self handleDatasourceExchangeWithSourceIndexPath:sourceIndexPath destinationIndexPath:destinationIndexPath withArray:sameSectionArray];

                }

            }

        }else{//插入到destinationIndexPath的尾部

            if (canChange) {

                if (sourceIndexPath == [NSIndexPath indexPathForRow:(destinationIndexPath.row + 1) inSection:destinationIndexPath.section]) {

                    [ZNSLLogTool logWithLevel:ZNSLLocalLogLevelInfo type:ZNSLLocalLogType_AUDIO_VIDEO content:@"ABC==:尾部,移动到原来的位置不用处理"];

                }else{

                    if (destinationIndexPath.row == (sameSectionArray.count - 1)) {//添加到最后一个元素

                        NSMutableArray *mutableArray = [NSMutableArray arrayWithArray:sameSectionArray];

                        OCFTFreeCombinationDataModel *sourceModel = mutableArray[sourceIndexPath.row];

                        sourceModel.excuteRoleShow = NO;

                        [mutableArray insertObject:sourceModel atIndex:destinationIndexPath.row + 1];

                        if (sourceIndexPath.row < mutableArray.count) {

                            [mutableArray removeObjectAtIndex:sourceIndexPath.row];

                        }else{

                            [ZNSLLogTool logWithLevel:ZNSLLocalLogLevelInfo type:ZNSLLocalLogType_AUDIO_VIDEO content:@"ABC==:移除数据不存在2"];

                            return;

                        }

                        for (NSInteger i = 0; i < mutableArray.count; i ++) {

                            OCFTFreeCombinationDataModel *model = mutableArray[i];

                            if (0 == i) {

                                model.excuteRoleShow = YES;

                            }else if(i == (mutableArray.count - 1)){

                                model.excuteRoleShow = NO;

                            }else{

                                model.excuteRoleShow = NO;

                            }

                        }

                        

                        [self.dataMutableArray replaceObjectAtIndex:destinationIndexPath.section withObject:[mutableArray copy]];

                    }else{

                        [self handleDatasourceExchangeWithSourceIndexPath:sourceIndexPath destinationIndexPath:destinationIndexPath withArray:sameSectionArray];

                    }

                }

            }

        }

    }else{//不同section移动

        [ZNSLLogTool logWithLevel:ZNSLLocalLogLevelInfo type:ZNSLLocalLogType_AUDIO_VIDEO content:@"ABC==:不同section移动"];

        NSMutableArray *sourceArray = [NSMutableArray arrayWithArray:self.dataMutableArray[sourceIndexPath.section]];

        NSMutableArray *destinationArray = [NSMutableArray arrayWithArray:self.dataMutableArray[destinationIndexPath.section]];

        OCFTFreeCombinationDataModel *sourceModel = sourceArray[sourceIndexPath.row];

        

        if (destinationFront) {//插入到destinationIndexPath的头部

            //目标数据

            if (destinationIndexPath.row == 0) {//插入到头部

                OCFTFreeCombinationDataModel *destinationModel = destinationArray[destinationIndexPath.row];

                destinationModel.excuteRoleShow = NO;

                

                sourceModel.excuteRoleShow = YES;

                [destinationArray insertObject:sourceModel atIndex:destinationIndexPath.row];

            }else if(destinationIndexPath.row == destinationArray.count){//插入到尾部

                sourceModel.excuteRoleShow = NO;

                [destinationArray insertObject:sourceModel atIndex:destinationIndexPath.row];

            }else{//插入到中间

                sourceModel.excuteRoleShow = NO;

                [destinationArray insertObject:sourceModel atIndex:destinationIndexPath.row];

                

            }

            [self.dataMutableArray replaceObjectAtIndex:destinationIndexPath.section withObject:[destinationArray copy]];

            

            //源数据

            if (sourceIndexPath.row == 0) {//移除头部

                if (1 == sourceArray.count) {

                    [sourceArray removeObject:sourceModel];

                }else if(sourceArray.count >= 2){

                    OCFTFreeCombinationDataModel *lastModel = sourceArray[sourceIndexPath.row + 1];

                    lastModel.excuteRoleShow = YES;

                    

                    [sourceArray removeObject:sourceModel];

                }

            }else if((sourceIndexPath.row + 1) == sourceArray.count){//移除尾部

                if (1 == sourceArray.count) {

                    [sourceArray removeObject:sourceModel];

                }else if(sourceArray.count >= 2){

                    [sourceArray removeObject:sourceModel];

                }

            }else{//移除中间

                [sourceArray removeObject:sourceModel];

            }

            

            [self.dataMutableArray replaceObjectAtIndex:sourceIndexPath.section withObject:[sourceArray copy]];

        }else{//插入到destinationIndexPath的尾部

            //目标数据

            if (destinationIndexPath.row == (destinationArray.count - 1)) {//添加到最后一个元素

                sourceModel.excuteRoleShow = NO;

                [destinationArray insertObject:sourceModel atIndex:destinationIndexPath.row + 1];

            }else{

                sourceModel.excuteRoleShow = NO;

                [destinationArray insertObject:sourceModel atIndex:destinationIndexPath.row + 1];

            }

            [self.dataMutableArray replaceObjectAtIndex:destinationIndexPath.section withObject:[destinationArray copy]];

            

            //源数据

            if (sourceIndexPath.row == 0) {//移除头部

                if (1 == sourceArray.count) {

                    [sourceArray removeObject:sourceModel];

                }else if(sourceArray.count >= 2){

                    OCFTFreeCombinationDataModel *lastModel = sourceArray[sourceIndexPath.row + 1];

                    lastModel.excuteRoleShow = YES;

                    

                    [sourceArray removeObject:sourceModel];

                }

            }else if((sourceIndexPath.row + 1) == sourceArray.count){//移除尾部

                if (1 == sourceArray.count) {

                    [sourceArray removeObject:sourceModel];

                }else if(sourceArray.count >= 2){

                    [sourceArray removeObject:sourceModel];

                }

            }else{//移除中间

                [sourceArray removeObject:sourceModel];

            }

            [self.dataMutableArray replaceObjectAtIndex:sourceIndexPath.section withObject:[sourceArray copy]];

        }

    }

    [self objArraToJSON:self.dataMutableArray];

}

  • (NSArray *)getDecorationView {

    NSMutableArray *viewArray = [NSMutableArray array];

    for (UIView *view in self.freeCollectionView.subviews) {

        if ([view isKindOfClass:[UICollectionSectionColorReusableView class]]) {

            [viewArray addObject:view];

        }

    }

    return viewArray;

}

#pragma mark  - UICollectionViewDataSource

  • (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {

//    ZNSLLog(@"ABC==:numberOfSections");

    return self.dataSourceArray.count;

}

  • (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {

//    ZNSLLog(@"ABC==:numberOfItems");

    NSArray *sectionArray = self.dataSourceArray[section];

    return sectionArray.count;

}

  • (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {

//    ZNSLLog(@"ABC==:cellForItemAtIndexPath:%ld,%ld",indexPath.section,(long)indexPath.row);

    OCFTFreeCombinationCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellIndentifier forIndexPath:indexPath];

    NSArray *sectionArray = self.dataSourceArray[indexPath.section];

    OCFTFreeCombinationDataModel *model = sectionArray[indexPath.row];

    cell.model = model;

    return cell;

}

  • (BOOL)collectionView:(UICollectionView *)collectionView canMoveItemAtIndexPath:(NSIndexPath *)indexPath {

    return YES;

}

  • (void)collectionView:(UICollectionView *)collectionView moveItemAtIndexPath:(NSIndexPath )sourceIndexPath toIndexPath:(NSIndexPath)destinationIndexPath {

//    ZNSLLog(@"ABC==:moveItemAtIndexPath,此回调方法不能删");

    [ZNSLLogTool logWithLevel:ZNSLLocalLogLevelInfo type:ZNSLLocalLogType_AUDIO_VIDEO content:@"ABC==:moveItemAtIndexPath,此回调方法不能删"];

}

  • (void)handleDatasourceExchangeWithSourceIndexPath:(NSIndexPath *)sourceIndexPath destinationIndexPath:(NSIndexPath *)destinationIndexPath withArray:(NSArray *)array

{

    NSMutableArray *tempArray = [NSMutableArray arrayWithArray:array];

    

    NSInteger activeRange = destinationIndexPath.item - sourceIndexPath.item;

    BOOL moveForward = activeRange > 0;

    NSInteger originIndex = 0;

    NSInteger targetIndex = 0;

    for (NSInteger i = 1; i <= labs(activeRange); i ++) {//移动元素

        NSInteger moveDirection = moveForward ? 1 : -1;

        originIndex =  sourceIndexPath.item + i * moveDirection;

        targetIndex = originIndex - 1 * moveDirection;

        

        OCFTFreeCombinationDataModel *originModel = tempArray[originIndex];

        OCFTFreeCombinationDataModel *targetModel = tempArray[targetIndex];

        if (0 == originIndex) {//头部

            if ((tempArray.count - 1) == targetIndex){//尾部

                originModel.excuteRoleShow = NO;

                

                targetModel.excuteRoleShow = YES;

            }else{//中间

                originModel.excuteRoleShow = NO;

                

                targetModel.excuteRoleShow = YES;

            }

        }else if ((tempArray.count - 1) == originIndex){//尾部

            if (0 == targetIndex){//头部

                originModel.excuteRoleShow = YES;

                

                targetModel.excuteRoleShow = NO;

            }else{//中间

                

            }

        }else{//中间

            if (0 == targetIndex) {//头部

                originModel.excuteRoleShow = YES;

                

                targetModel.excuteRoleShow = NO;

            }else if ((tempArray.count - 1) == targetIndex){//尾部

            }else{//中间

            }

        }

        

        [tempArray exchangeObjectAtIndex:originIndex withObjectAtIndex:targetIndex];

    }

    [self.dataMutableArray replaceObjectAtIndex:destinationIndexPath.section withObject:[tempArray copy]];

}

  • (NSString *)objArraToJSON:(NSArray *)array {

    NSString *jsonStr = @"";

    for (NSInteger i = 0; i < array.count; i ++) {

        NSArray *tempArray = array[i];

        if (0 == tempArray.count) {

            [ZNSLLogTool logWithLevel:ZNSLLocalLogLevelInfo type:ZNSLLocalLogType_AUDIO_VIDEO content:[NSString stringWithFormat:@"ABC==第%ld组:空",(i + 1)]];

        }else{

            for (NSInteger j = 0; j <tempArray.count ; j ++) {

                OCFTFreeCombinationDataModel *model = tempArray[j];

                if (0 == j) {

                    jsonStr =  [jsonStr stringByAppendingString:model.name];

                }else{

                    jsonStr = [jsonStr stringByAppendingString:[NSString stringWithFormat:@",%@",model.name]];

                }

            }

            ZNSLLog(@"ABC==第%ld组:%@",(i + 1),jsonStr);

            [ZNSLLogTool logWithLevel:ZNSLLocalLogLevelInfo type:ZNSLLocalLogType_AUDIO_VIDEO content:[NSString stringWithFormat:@"ABC==第%ld组:%@",(i + 1),jsonStr]];

            jsonStr = @"";

        }

    }

    return jsonStr;

}

#pragma mark - UICollectionViewDelegate

//拖动时固定Cell不被挤压

  • (NSIndexPath *)collectionView:(UICollectionView *)collectionView targetIndexPathForMoveFromItemAtIndexPath:(NSIndexPath *)originalIndexPath toProposedIndexPath:(NSIndexPath *)proposedIndexPath {

//    ZNSLLog(@"ABC==:targetIndexPathForMoveFromItemAtIndexPath");

    return originalIndexPath;

}

#pragma mark - UICollectionViewDelegateFlowLayout

//定义每个Item的大小

  • (CGSize)collectionView:(UICollectionView )collectionView layout:(UICollectionViewLayout)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {

    CGFloat itemWidth = ([UIScreen mainScreen].bounds.size.width - 32 - 7)/3.f;

    if (itemWidth < OCFTItemWidth) {

        return CGSizeMake(itemWidth, 44.f);

    }else{

        return CGSizeMake(115.f, 44.f);

    }

}

//通过调整inset使单元格顶部和底部都有间距(inset次序: 上,左,下,右边)

  • (UIEdgeInsets)collectionView:(UICollectionView )collectionView layout:(UICollectionViewLayout)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {

    NSArray *array = self.dataSourceArray[section];

    if (0 == array.count) {

        return UIEdgeInsetsZero;

    }else{

        return UIEdgeInsetsMake(8, 7, 8, 0);

    }

}

//设置单元格间的横向间距

  • (CGFloat)collectionView:(UICollectionView )collectionView layout:(UICollectionViewLayout)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section {

    return 0.f;

}

//设置纵向的行间距

  • (CGFloat)collectionView:(UICollectionView )collectionView layout:(UICollectionViewLayout)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section {

    return 0.f;

}

#pragma mark - OCFTUICollectionViewDelegateLeftAlignedFlowLayout

  • (UIColor *)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout backgroundColorForSection:(NSInteger)section {

   return [UIColor whiteColor];

}

  • (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout cornerRadiusForSection:(NSInteger)section {

    return 4.f;

}

  • (UIColor *)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout shadowColorForSection:(NSInteger)section {

    return [UIColor colorWithRed:0.f green:0.f blue:0.f alpha:0.15f];

}

  • (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout shadowRadiusForSection:(NSInteger)section {

   return 4.36;

}

#pragma mark - getter and setter

  • (UICollectionView *)freeCollectionView {

    if (!_freeCollectionView) {

        OCFTUICollectionViewLeftAlignedFlowLayout *leftAlignedLayout = [[OCFTUICollectionViewLeftAlignedFlowLayout alloc]init];

        _freeCollectionView = [[UICollectionView alloc]initWithFrame:CGRectZero collectionViewLayout:leftAlignedLayout];

        _freeCollectionView.dataSource = self;

        _freeCollectionView.backgroundColor = UIColorFromHex(0xFAFAFA);

        _freeCollectionView.layer.masksToBounds = YES;

        _freeCollectionView.layer.cornerRadius = 4.f;

        _freeCollectionView.delegate  = self;

        [_freeCollectionView registerClass:[OCFTFreeCombinationCollectionViewCell class] forCellWithReuseIdentifier:cellIndentifier];

    }

    return _freeCollectionView;

}

@end