一个UICollectionView自定义layout的实现

#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的实现的更多相关文章
- UICollectionView Layout自定义 Layout布局
from: http://www.tuicool.com/articles/vuyIriN 当我们使用系统自带的UICollectionViewFlowLayout无法实现我们的布局时,我们就可以 ...
- UICollectionView之自定义Layout
#import <UIKit/UIKit.h> @interface WQViewController : UIViewController - (id)initWithFrame:(CG ...
- 自定义 Layout布局 UICollectionViewLayout
from: http://www.tuicool.com/articles/vuyIriN 当我们使用系统自带的UICollectionViewFlowLayout无法实现我们的布局时,我们就可以 ...
- 安卓自定义控件(四)实现自定义Layout
本来我是不准备写这篇文章的,我实在想不出有什么样奇怪的理由,会去继承ViewGroup然后自定义一个布局,大概是我的项目经验还不够吧,想了好久,想到了这样一个需求: 需求 如图:在项目中经常有一个这样 ...
- UICollectionView自定义cell布局layout
写一个类继承UICollectionViewLayout,这个类需要提供一个数组来标识各个cell的属性信息,包括位置,size大小,返回一个UICollectionViewLayoutAttribu ...
- UICollectionView的水平流水布局自定义layout
最近做合创共美的商城项目,遇到发货地址的不配送地区,是做一个弹出框,弹出框的布局是根据地名字数长短不齐的标签. 本来也可以用tableview来做的.只不过多建几个tableviewcell就可以了. ...
- iOS开发之窥探UICollectionViewController(三) --使用UICollectionView自定义瀑布流
上篇博客的实例是自带的UICollectionViewDelegateFlowLayout布局基础上来做的Demo, 详情请看<iOS开发之窥探UICollectionViewControlle ...
- 利用UICollectionViewFlowLayout的隐式动画实现UICollectionView的layout的动画调整(外加放大指定cell效果)
前几天在gitHub看到个不错的效果,就是DaiExpandCollectionView,效果如图: 所以赶紧下下来源码看看他怎么实现的,打开源码看了半天,发现他没写什么关于动画的代码啊... 经 ...
- 用NSCalendar和UICollectionView自定义日历,并实现签到显示
前一段时间因为工作需要实现了一个可以签到的日历,来记录一下实现的思路 效果如图: 这里的基本需求是: 1,显示用户某个月的签到情况,已经签到的日子打个圈,没有签到且在某个时间范围内的可以签到,其他 ...
随机推荐
- 俞昆20155335《网络对抗》MSF基础应用
- shell开发规范
版本1.0版,参考网上的一些文章规整而来.后期打算继续修改.完成一篇适合自己的shell开发规范. 最新编辑时间:2017.6.25 一. 命名规范 1. 版本和运行参数 1) 脚本开始之前以注释形式 ...
- 【译】第十五篇 Integration Services:SSIS参数
本篇文章是Integration Services系列的第十五篇,详细内容请参考原文. 简介在前一篇,我们使用SSDT-BI将第一个SSIS项目My_First_SSIS_Project升级/转换到S ...
- Dummynet模拟高时延网络场景(Windows7)
如果安装时出现:my_socket failed 2, cannot talk to kernel module 请查看是否以管理员方式运行,如果是,再判断当前操作系统是否为Win7 64位,如果是, ...
- Linux内核Ramdisk(initrd)机制【转】
转自:http://www.cnblogs.com/armlinux/archive/2011/03/30/2396827.html 摘要:对于Linux用户来说,Ramdisk并不陌生,可是为什么需 ...
- Linux学习笔记-文件处理和权限命令
目录 文件处理命令 touch cat tac more less head tail 链接命令 ln 权限命令 chmod 权限管理命令 chown chgrp umask 文件处理命令 touch ...
- 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 ...
- MongoDB安全:创建第1个、第2个、第3个用户
Windows 10家庭中文版,MongoDB3.6.3, 前言 使用mongod命令基于某个空白文件夹(存放数据)启动MongoDB服务器时,要是没有使用--auth选项,启动后,任何客户端是可以无 ...
- CVE-2012-1876Microsoft Internet Explorer Col元素远程代码执行漏洞分析
Microsoft Internet Explorer是微软Windows操作系统中默认捆绑的WEB浏览器. Microsoft Internet Explorer 6至9版本中存在漏 ...
- fedora常见问题和解决方案
fedora作为linux主流发行版之一,大部分功能还是很赞的.只是在美观性和其他一些细节上还是需要手工调整才有更加体验. 以下解决方案,使用fedora20+gnome3环境 eclipse界面难看 ...