一个UICollectionView自定义layout的实现

一个UICollectionView自定义layout的实现
 
一个UICollectionView自定义layout的实现
#import <UIKit/UIKit.h>



@interface AppDelegate : UIResponder <UIApplicationDelegate>



@property (strong, nonatomic) UIWindow *window;



@property (strong, nonatomic) NSMutableArray *letterArray;



@end
AppDelegate.h
一个UICollectionView自定义layout的实现
#import "AppDelegate.h"



@interface AppDelegate ()



@end



@implementation AppDelegate



- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

{

    self.letterArray = [NSMutableArray array];

    for(int i=0; i<26; i++)

    {

        [self.letterArray addObject:[NSString stringWithFormat:@"%C",(unichar)(65+i)]];

    }

    

    return YES;

}
AppDelegate.m

 

一个UICollectionView自定义layout的实现
#import <UIKit/UIKit.h>



@interface ViewController : UIViewController



@end
ViewController.h
一个UICollectionView自定义layout的实现
#import "ViewController.h"

#import "AppDelegate.h"

#import "CollectionViewDataSource.h"

#import "DraggableCircleLayout.h"

#import "LSCollectionViewHelper.h"



@interface ViewController ()

{

    UICollectionView *collectionView;

    CollectionViewDataSource *cvDataSource;

}

@end



@implementation ViewController



- (IBAction)ChangeLayoutClickHandler:(id)sender

{

    if([collectionView.collectionViewLayout isKindOfClass:[CircleLayout class]])

    {

        UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];

        collectionView.collectionViewLayout = layout;

    }

    else

    {

        CircleLayout *layout = [[CircleLayout alloc] init];

        collectionView.collectionViewLayout = layout;

    }

}



- (IBAction)BatchUploadClickHandler:(id)sender

{

    //这里有个细节需要注意,最好是将删除操作放在添加操作前面,因为无论你顺序如何,始终都会先执行删除操作。

    //如果代码顺序是先添加后删除,但实际执行顺序是先删除后添加,可能会因为索引不对影响代码逻辑。

    [collectionView performBatchUpdates:^{

        NSMutableArray *letterArray = [self getLetterArray];

        //删除四个元素

        NSIndexPath *path1 = [NSIndexPath indexPathForItem:0 inSection:0];

        NSIndexPath *path2 = [NSIndexPath indexPathForItem:1 inSection:0];

        NSIndexPath *path3 = [NSIndexPath indexPathForItem:2 inSection:0];

        NSIndexPath *path4 = [NSIndexPath indexPathForItem:3 inSection:0];

        

        NSIndexSet *indexSet = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0,4)];

        

        [indexSet enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop){

            NSLog(@"%lu", (unsigned long)idx);

        }];

        

        [letterArray removeObjectsAtIndexes:indexSet];



        NSArray *array = [NSArray arrayWithObjects:path1, path2, path3, path4, nil];

        [collectionView deleteItemsAtIndexPaths:array];

        

        //添加一个元素

        [letterArray addObject:@"1"];

        

        [collectionView insertItemsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForItem:letterArray.count-1 inSection:0]]];

    } completion:nil];

}



- (void)viewDidLoad

{

    [super viewDidLoad];



//    UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];

//    CircleLayout *layout = [[CircleLayout alloc] init];

    DraggableCircleLayout *layout = [[DraggableCircleLayout alloc] init];

    

    collectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(10, 50, 300, 400) collectionViewLayout:layout];

    

    collectionView.backgroundColor = [UIColor grayColor];

    collectionView.draggable = YES;

    

    [collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"LetterCell"];

    [collectionView registerClass:[UICollectionReusableView class] forSupplementaryViewOfKind:@"FirstSupplementary" withReuseIdentifier:@"ReuseID"];

    [collectionView registerClass:[UICollectionReusableView class] forSupplementaryViewOfKind:@"SecondSupplementary" withReuseIdentifier:@"ReuseID"];    

    

    cvDataSource = [CollectionViewDataSource alloc];

    collectionView.dataSource = cvDataSource;

    collectionView.delegate = cvDataSource;

    

    [self.view addSubview:collectionView];



    UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapGestureHandler:)];

    [collectionView addGestureRecognizer:tapRecognizer];

}



- (void)tapGestureHandler:(UITapGestureRecognizer *)sender

{

    CGPoint point = [sender locationInView:collectionView];

    NSIndexPath *tappedCellPath = [collectionView indexPathForItemAtPoint:point];

    

    NSMutableArray *letterArray = [self getLetterArray];

    if(tappedCellPath)

    {

        //删除点击的cell

        [letterArray removeObjectAtIndex:tappedCellPath.item];

        [collectionView deleteItemsAtIndexPaths:[NSArray arrayWithObject:tappedCellPath]];

    }

    else

    {

        //如果点击空白处,在末尾添加一个随机小写字母

        unichar asciiX = (unichar)[self getRandomNumber:97 to:97+26];

        [letterArray addObject:[NSString stringWithFormat:@"%C",asciiX]];

        NSIndexPath *path = [NSIndexPath indexPathForItem:letterArray.count-1 inSection:0];

        [collectionView insertItemsAtIndexPaths:[NSArray arrayWithObject:path]];

    }

}



- (NSMutableArray *)getLetterArray

{

    AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];

    

    return appDelegate.letterArray;

}



- (int)getRandomNumber:(int)from to:(int)to

{

    return (int)(from + (arc4random() % (to-from)));

}



- (void)didReceiveMemoryWarning {

    [super didReceiveMemoryWarning];

    // Dispose of any resources that can be recreated.

}



@end
ViewController.m

 

一个UICollectionView自定义layout的实现
#import <UIKit/UIKit.h>

#import "UICollectionView+Draggable.h"



@interface CollectionViewDataSource : NSObject<UICollectionViewDataSource_Draggable, UICollectionViewDelegate>



@end
CollectionViewDataSource.h
一个UICollectionView自定义layout的实现
#import <Foundation/Foundation.h>

#import "AppDelegate.h"

#import "CollectionViewDataSource.h"



@implementation CollectionViewDataSource





- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView

{

    return 1;

}



- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section

{

    return [self getLetterArray].count;

}



- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath

{

    UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"LetterCell" forIndexPath:indexPath];

    

    //先移除可重用cell里面的子元素(否则会出现新旧交叠)

    [cell.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];



    cell.backgroundColor = [UIColor yellowColor];

    

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

    label.text = [[self getLetterArray] objectAtIndex:indexPath.row];

    label.font = [UIFont systemFontOfSize:12];

    [label sizeToFit];

    label.center = CGPointMake(cell.bounds.size.width/2, cell.bounds.size.height/2);

    [cell addSubview:label];

    

    return cell;

}



- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath

{

    UICollectionReusableView *view = [collectionView dequeueReusableSupplementaryViewOfKind:kind withReuseIdentifier:@"ReuseID" forIndexPath:indexPath];

    

    view.backgroundColor = [UIColor greenColor];

    

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

    label.text = kind;

    label.font = [UIFont systemFontOfSize:24];

    [label sizeToFit];

    label.center = CGPointMake(view.bounds.size.width/2, view.bounds.size.height/2);

    [view addSubview:label];

    

    return view;

}





- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath

{

    NSLog(@"你选择了");

    

//    [self.myArray removeObjectAtIndex:indexPath.row];

//    

//    [collectionView deleteItemsAtIndexPaths:[NSArray arrayWithObject:indexPath]];

}



- (BOOL)collectionView:(LSCollectionViewHelper *)collectionView canMoveItemAtIndexPath:(NSIndexPath *)indexPath

{

    NSLog(@"canMoveItemAtIndexPath");

    return YES;

}



- (void)collectionView:(LSCollectionViewHelper *)collectionView moveItemAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath

{

    NSLog(@"moveItemAtIndexPath");

    

    NSMutableArray *data = [self getLetterArray];

    

    NSNumber *index = [data objectAtIndex:fromIndexPath.item];

    [data removeObjectAtIndex:fromIndexPath.item];

    [data insertObject:index atIndex:toIndexPath.item];

}



- (NSMutableArray *)getLetterArray

{

    AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];

    

    return appDelegate.letterArray;

}



@end
CollectionViewDataSource.m

 

一个UICollectionView自定义layout的实现
#import <UIKit/UIKit.h>



@interface MyCollectionReusableView : UICollectionReusableView



@end
MyCollectionReusableView.h
一个UICollectionView自定义layout的实现
#import "MyCollectionReusableView.h"



@implementation MyCollectionReusableView



- (instancetype)initWithFrame:(CGRect)frame

{

    self = [super initWithFrame:frame];

    

    if (self)

    {

        self.backgroundColor = [UIColor orangeColor];

        

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

        label.text = @"Decoration View";

        label.font = [UIFont systemFontOfSize:18];

        [label sizeToFit];

        label.center = CGPointMake(frame.size.width/2, frame.size.height/2);

        [self addSubview:label];

    }

    

    return self;

}



@end
MyCollectionReusableView.m

 

一个UICollectionView自定义layout的实现
#import <UIKit/UIKit.h>



@interface CircleLayout : UICollectionViewLayout



@end
CircleLayout.h
一个UICollectionView自定义layout的实现
#import "AppDelegate.h"

#import "CircleLayout.h"

#import "CollectionViewDataSource.h"

#import "MyCollectionReusableView.h"



@interface CircleLayout()

{

    CGSize cvSize;

    CGPoint cvCenter;

    CGFloat radius;

    NSInteger cellCount;

}



@property (strong, nonatomic) NSMutableArray *indexPathsToAnimate;



@end



@implementation CircleLayout



- (void)prepareLayout

{

    [super prepareLayout];

    

    [self registerClass:[MyCollectionReusableView class] forDecorationViewOfKind:@"MyDecoration"];

    

    cvSize = self.collectionView.frame.size;

    cellCount = [self.collectionView numberOfItemsInSection:0];

    cvCenter = CGPointMake(cvSize.width / 2.0, cvSize.height / 2.0);

    radius = MIN(cvSize.width, cvSize.height) / 2.5;

}



- (CGSize)collectionViewContentSize

{

    return self.collectionView.bounds.size;

}



- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect

{

    NSMutableArray *array = [NSMutableArray array];

    

    //add cells

    for (int i=0; i<cellCount; i++)

    {

        NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0];

        

        UICollectionViewLayoutAttributes *attributes = [self layoutAttributesForItemAtIndexPath:indexPath];

        

        [array addObject:attributes];

    }

    

    //add first supplementaryView

    NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:0];

    UICollectionViewLayoutAttributes *attributes = [self layoutAttributesForSupplementaryViewOfKind:@"FirstSupplementary" atIndexPath:indexPath];

    [array addObject:attributes];

    

    //add second supplementaryView

    attributes = [self layoutAttributesForSupplementaryViewOfKind:@"SecondSupplementary" atIndexPath:indexPath];

    [array addObject:attributes];

    

    //add decorationView

    attributes = [self layoutAttributesForDecorationViewOfKind:@"MyDecoration" atIndexPath:indexPath];

    [array addObject:attributes];

    

    return array;

}



- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath

{

    UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];



    attributes.size = CGSizeMake(20, 20);

    attributes.center = CGPointMake(cvCenter.x + radius * cosf(2 * indexPath.item * M_PI / cellCount),

                                    cvCenter.y + radius * sinf(2 * indexPath.item * M_PI / cellCount));

    

    return attributes;

}



- (UICollectionViewLayoutAttributes *)layoutAttributesForSupplementaryViewOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath

{

    UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForSupplementaryViewOfKind:elementKind withIndexPath:indexPath];

    

    attributes.size = CGSizeMake(260, 40);

    if([elementKind isEqual:@"FirstSupplementary"])

    {

        attributes.center = CGPointMake(cvSize.width/2, 40);

    }

    else

    {

        attributes.center = CGPointMake(cvSize.width/2, cvSize.height-40);

    }

    

    return attributes;

}



- (UICollectionViewLayoutAttributes *)layoutAttributesForDecorationViewOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath

{

    UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForDecorationViewOfKind:elementKind withIndexPath:indexPath];



    attributes.size = CGSizeMake(140, 40);

    attributes.center = CGPointMake(cvSize.width/2, cvSize.height/2);

    

    return attributes;

}



//当边界更改时是否更新布局

- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds

{

    CGRect oldBounds = self.collectionView.bounds;

    

    if (CGRectGetWidth(newBounds) != CGRectGetWidth(oldBounds))

    {

        return YES;

    }

    

    return NO;

}



//通知布局,collection view里有元素即将改变,这里可以收集改变的元素indexPath和action类型。

-(void)prepareForCollectionViewUpdates:(NSArray *)updateItems

{

    [super prepareForCollectionViewUpdates:updateItems];

    

    NSMutableArray *indexPaths = [NSMutableArray array];

    

    for(UICollectionViewUpdateItem *updateItem in updateItems)

    {

        //UICollectionUpdateActionInsert,

        //UICollectionUpdateActionDelete,

        //UICollectionUpdateActionReload,

        //UICollectionUpdateActionMove,

        //UICollectionUpdateActionNone

        

        NSLog(@"before index:%d,after index:%d,action:%d", updateItem.indexPathBeforeUpdate.row,updateItem.indexPathAfterUpdate.row,updateItem.updateAction);

        

        switch (updateItem.updateAction) {

            case UICollectionUpdateActionInsert:

                [indexPaths addObject:updateItem.indexPathAfterUpdate];

                break;

            case UICollectionUpdateActionDelete:

                [indexPaths addObject:updateItem.indexPathBeforeUpdate];

                break;

            case UICollectionUpdateActionMove:

                [indexPaths addObject:updateItem.indexPathBeforeUpdate];

                [indexPaths addObject:updateItem.indexPathAfterUpdate];

                break;

            default:

                NSLog(@"unhandled case: %@", updateItem);

                break;

        }

    }

    

    self.indexPathsToAnimate = indexPaths;

}



//当一个元素被插入collection view时,返回它的初始布局,这里可以加入一些动画效果。

- (UICollectionViewLayoutAttributes *)initialLayoutAttributesForAppearingItemAtIndexPath:(NSIndexPath *)itemIndexPath

{

    UICollectionViewLayoutAttributes *attr = [self layoutAttributesForItemAtIndexPath:itemIndexPath];

    

    if([self.indexPathsToAnimate containsObject:itemIndexPath])

    {

        attr.transform = CGAffineTransformRotate(CGAffineTransformMakeScale(10,10),M_PI);

        attr.center = CGPointMake(CGRectGetMidX(self.collectionView.bounds), CGRectGetMidY(self.collectionView.bounds));

        [self.indexPathsToAnimate removeObject:itemIndexPath];

    }

    

    return attr;

}







- (NSArray *)getLetterArray

{

    AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];

    

    return appDelegate.letterArray;

}



@end
CircleLayout.m

 

一个UICollectionView自定义layout的实现
#import "CircleLayout.h"

#import "UICollectionViewLayout_Warpable.h"



@interface DraggableCircleLayout : CircleLayout <UICollectionViewLayout_Warpable>



@property (readonly, nonatomic) LSCollectionViewLayoutHelper *layoutHelper;



@end
DraggableCircleLayout.h
一个UICollectionView自定义layout的实现
#import "DraggableCircleLayout.h"

#import "LSCollectionViewLayoutHelper.h"



@interface DraggableCircleLayout()

{

    LSCollectionViewLayoutHelper *_layoutHelper;

}

@end



@implementation DraggableCircleLayout



- (LSCollectionViewLayoutHelper *)layoutHelper

{

    if(_layoutHelper == nil) {

        _layoutHelper = [[LSCollectionViewLayoutHelper alloc] initWithCollectionViewLayout:self];

    }

    return _layoutHelper;

}



- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect

{

    return [self.layoutHelper modifiedLayoutAttributesForElements:[super layoutAttributesForElementsInRect:rect]];

}



@end
DraggableCircleLayout.m

 

你可能感兴趣的:(Collection)