#import <UIKit/UIKit.h>

@interface AppDelegate : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow *window;

@property (strong, nonatomic) NSMutableArray *letterArray;

@end

AppDelegate.h

#import "AppDelegate.h"

@interface AppDelegate ()

@end

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.letterArray = [NSMutableArray array];
for(int i=; i<; i++)
{
[self.letterArray addObject:[NSString stringWithFormat:@"%C",(unichar)(+i)]];
} return YES;
}

AppDelegate.m

#import <UIKit/UIKit.h>

@interface ViewController : UIViewController

@end

ViewController.h

#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: inSection:];
NSIndexPath *path2 = [NSIndexPath indexPathForItem: inSection:];
NSIndexPath *path3 = [NSIndexPath indexPathForItem: inSection:];
NSIndexPath *path4 = [NSIndexPath indexPathForItem: inSection:]; NSIndexSet *indexSet = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(,)]; [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:@""]; [collectionView insertItemsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForItem:letterArray.count- inSection:]]];
} 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(, , , ) 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: to:+];
[letterArray addObject:[NSString stringWithFormat:@"%C",asciiX]];
NSIndexPath *path = [NSIndexPath indexPathForItem:letterArray.count- inSection:];
[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

#import <UIKit/UIKit.h>
#import "UICollectionView+Draggable.h" @interface CollectionViewDataSource : NSObject<UICollectionViewDataSource_Draggable, UICollectionViewDelegate> @end

CollectionViewDataSource.h

#import <Foundation/Foundation.h>
#import "AppDelegate.h"
#import "CollectionViewDataSource.h" @implementation CollectionViewDataSource - (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
return ;
} - (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:];
[label sizeToFit];
label.center = CGPointMake(cell.bounds.size.width/, cell.bounds.size.height/);
[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:];
[label sizeToFit];
label.center = CGPointMake(view.bounds.size.width/, view.bounds.size.height/);
[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

#import <UIKit/UIKit.h>

@interface MyCollectionReusableView : UICollectionReusableView

@end

MyCollectionReusableView.h

#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:];
[label sizeToFit];
label.center = CGPointMake(frame.size.width/, frame.size.height/);
[self addSubview:label];
} return self;
} @end

MyCollectionReusableView.m

#import <UIKit/UIKit.h>

@interface CircleLayout : UICollectionViewLayout

@end

CircleLayout.h

#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:];
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=; i<cellCount; i++)
{
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:]; UICollectionViewLayoutAttributes *attributes = [self layoutAttributesForItemAtIndexPath:indexPath]; [array addObject:attributes];
} //add first supplementaryView
NSIndexPath *indexPath = [NSIndexPath indexPathForItem: inSection:];
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(, );
attributes.center = CGPointMake(cvCenter.x + radius * cosf( * indexPath.item * M_PI / cellCount),
cvCenter.y + radius * sinf( * indexPath.item * M_PI / cellCount)); return attributes;
} - (UICollectionViewLayoutAttributes *)layoutAttributesForSupplementaryViewOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForSupplementaryViewOfKind:elementKind withIndexPath:indexPath]; attributes.size = CGSizeMake(, );
if([elementKind isEqual:@"FirstSupplementary"])
{
attributes.center = CGPointMake(cvSize.width/, );
}
else
{
attributes.center = CGPointMake(cvSize.width/, cvSize.height-);
} return attributes;
} - (UICollectionViewLayoutAttributes *)layoutAttributesForDecorationViewOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForDecorationViewOfKind:elementKind withIndexPath:indexPath]; attributes.size = CGSizeMake(, );
attributes.center = CGPointMake(cvSize.width/, cvSize.height/); 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(,),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

#import "CircleLayout.h"
#import "UICollectionViewLayout_Warpable.h" @interface DraggableCircleLayout : CircleLayout <UICollectionViewLayout_Warpable> @property (readonly, nonatomic) LSCollectionViewLayoutHelper *layoutHelper; @end

DraggableCircleLayout.h

#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

一个UICollectionView自定义layout的实现的更多相关文章

  1. UICollectionView Layout自定义 Layout布局

    from:   http://www.tuicool.com/articles/vuyIriN 当我们使用系统自带的UICollectionViewFlowLayout无法实现我们的布局时,我们就可以 ...

  2. UICollectionView之自定义Layout

    #import <UIKit/UIKit.h> @interface WQViewController : UIViewController - (id)initWithFrame:(CG ...

  3. 自定义 Layout布局 UICollectionViewLayout

    from:   http://www.tuicool.com/articles/vuyIriN 当我们使用系统自带的UICollectionViewFlowLayout无法实现我们的布局时,我们就可以 ...

  4. 安卓自定义控件(四)实现自定义Layout

    本来我是不准备写这篇文章的,我实在想不出有什么样奇怪的理由,会去继承ViewGroup然后自定义一个布局,大概是我的项目经验还不够吧,想了好久,想到了这样一个需求: 需求 如图:在项目中经常有一个这样 ...

  5. UICollectionView自定义cell布局layout

    写一个类继承UICollectionViewLayout,这个类需要提供一个数组来标识各个cell的属性信息,包括位置,size大小,返回一个UICollectionViewLayoutAttribu ...

  6. UICollectionView的水平流水布局自定义layout

    最近做合创共美的商城项目,遇到发货地址的不配送地区,是做一个弹出框,弹出框的布局是根据地名字数长短不齐的标签. 本来也可以用tableview来做的.只不过多建几个tableviewcell就可以了. ...

  7. iOS开发之窥探UICollectionViewController(三) --使用UICollectionView自定义瀑布流

    上篇博客的实例是自带的UICollectionViewDelegateFlowLayout布局基础上来做的Demo, 详情请看<iOS开发之窥探UICollectionViewControlle ...

  8. 利用UICollectionViewFlowLayout的隐式动画实现UICollectionView的layout的动画调整(外加放大指定cell效果)

    前几天在gitHub看到个不错的效果,就是DaiExpandCollectionView,效果如图:   所以赶紧下下来源码看看他怎么实现的,打开源码看了半天,发现他没写什么关于动画的代码啊... 经 ...

  9. 用NSCalendar和UICollectionView自定义日历,并实现签到显示

    前一段时间因为工作需要实现了一个可以签到的日历,来记录一下实现的思路 效果如图:   这里的基本需求是: 1,显示用户某个月的签到情况,已经签到的日子打个圈,没有签到且在某个时间范围内的可以签到,其他 ...

随机推荐

  1. 俞昆20155335《网络对抗》MSF基础应用

  2. shell开发规范

    版本1.0版,参考网上的一些文章规整而来.后期打算继续修改.完成一篇适合自己的shell开发规范. 最新编辑时间:2017.6.25 一. 命名规范 1. 版本和运行参数 1) 脚本开始之前以注释形式 ...

  3. 【译】第十五篇 Integration Services:SSIS参数

    本篇文章是Integration Services系列的第十五篇,详细内容请参考原文. 简介在前一篇,我们使用SSDT-BI将第一个SSIS项目My_First_SSIS_Project升级/转换到S ...

  4. Dummynet模拟高时延网络场景(Windows7)

    如果安装时出现:my_socket failed 2, cannot talk to kernel module 请查看是否以管理员方式运行,如果是,再判断当前操作系统是否为Win7 64位,如果是, ...

  5. Linux内核Ramdisk(initrd)机制【转】

    转自:http://www.cnblogs.com/armlinux/archive/2011/03/30/2396827.html 摘要:对于Linux用户来说,Ramdisk并不陌生,可是为什么需 ...

  6. Linux学习笔记-文件处理和权限命令

    目录 文件处理命令 touch cat tac more less head tail 链接命令 ln 权限命令 chmod 权限管理命令 chown chgrp umask 文件处理命令 touch ...

  7. 04 Go 1.4 Release Notes

    Go 1.4 Release Notes Introduction to Go 1.4 Changes to the language For-range loops Method calls on ...

  8. MongoDB安全:创建第1个、第2个、第3个用户

    Windows 10家庭中文版,MongoDB3.6.3, 前言 使用mongod命令基于某个空白文件夹(存放数据)启动MongoDB服务器时,要是没有使用--auth选项,启动后,任何客户端是可以无 ...

  9. CVE-2012-1876Microsoft Internet Explorer Col元素远程代码执行漏洞分析

    Microsoft Internet Explorer是微软Windows操作系统中默认捆绑的WEB浏览器.         Microsoft Internet Explorer 6至9版本中存在漏 ...

  10. fedora常见问题和解决方案

    fedora作为linux主流发行版之一,大部分功能还是很赞的.只是在美观性和其他一些细节上还是需要手工调整才有更加体验. 以下解决方案,使用fedora20+gnome3环境 eclipse界面难看 ...