一个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,显示用户某个月的签到情况,已经签到的日子打个圈,没有签到且在某个时间范围内的可以签到,其他 ...
随机推荐
- 20155222 2016-2017-2 《Java程序设计》第7周学习总结
20155222 2016-2017-2 <Java程序设计>第7周学习总结 教材学习内容总结 使用基于方法的语法在 Enumerable 类中调用 Where 方法时(像在 LINQ t ...
- Dynamic Rankings(动态第k大+树套树)
题目链接: http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1112 题目: 思路: 树套树板子题. 代码实现如下: #inclu ...
- Happy Matt Friends(HDU5119 + dp)
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5119 题目: 题意: 求选择任意个数,使其异或和大于等于m的方案数. 思路: 每个数有选和不选两种方 ...
- meterpreter使用
1.基本命令 background:将meterpreter终端隐藏在后台 sessions:查看已经成功获取的会话,想继续与某会话进行交互使用sessions –i quit:直接关闭当前meter ...
- 20165227 学习基础和C语言基础调查
学习基础和C语言基础调查 技能学习经验和感悟 你有什么技能比大多人(超过90%以上)更好? 如果非要说出来一个的话,那就是篮球了.从热爱篮球,到热爱打篮球,经历挫折阻碍,不断反思学习,一步一步地向前迈 ...
- 【记录】尝试用QEMU模拟ARM开发板去加载并运行Uboot,kernel,rootfs【转】
转自:https://www.crifan.com/try_use_qemu_emulate_arm_board_to_load_and_run_uboot_kernel_rootfs/ [背景] 手 ...
- 四、springcloud之服务调用Feign(二)
一.Fegin的常见应用 Feign的Encoder.Decoder和ErrorDecoder Feign将方法签名中方法参数对象序列化为请求参数放到HTTP请求中的过程,是由编码器(Encoder) ...
- Apache HBase Performance Tuning 官文总结
Apache HBase Performance Tuning RAM, RAM, RAM. 不要让HBase饿死. 请使用64位的平台 必须将swapping设定为0 使用本地硬件来完成hdfs的c ...
- Flask:初次使用Blueprints
Windows 10家庭中文版,Python 3.6.4,Flask 1.0.2,Eclipse Oxygen.1a Release (4.7.1a),PyDev 6.3.2 本文为记录自己第一次使用 ...
- java基础75 xpth技术(网页知识)
1.xpth技术 1.1.xpath的作用 主要用于快速获取所需的节点对象. list<Node> selectNodes("xpath"); 查询多个节点对象 ...