一个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,显示用户某个月的签到情况,已经签到的日子打个圈,没有签到且在某个时间范围内的可以签到,其他 ...
随机推荐
- PartyPlay发布版
发布版本在beta版本的基础之上修改了pose王中的显示函数部分,使其可以正常的多次显示不同图片,不会出现卡在一张图片的问题上. 因此总的发布版本内容: 1.谁是卧底: 点击进入谁是卧底,进入游戏前的 ...
- HTML字体的设置
CSS字体设置 box-sizing:border #content-box box-shadow:设置盒子边框的阴影. 字体动作: font-family:设置字体.比如:‘微软雅黑 ...
- Linux/Unix系统编程手册 第二章:基本概念
本章预热与后续系统编程有关的概念. 术语“操作系统”通常包含2种含义:一是指完整的软件包,包括管理计算机资源的核心组件,已经附带的标准软件:二是独指管理硬件的内核. 内核具有诸多概功能,包括: 进程管 ...
- Html5使用history对象history.pushState()和history.replaceState()方法添加和修改浏览历史记录
根据网上参考自己做个笔记:参考网址:http://javascript.ruanyifeng.com/bom/history.html history.pushState() HTML5为histor ...
- Red Hat Enterprise Linux 7.2下使用RPM包安装SQL Server vNext
1.下载安装包 mssql-server:https://packages.microsoft.com/rhel/7/mssql-server/ mssql-tools:https://package ...
- java四舍五入BigDecimal和js保留小数点两位
java四舍五入BigDecimal保留两位小数的实现方法: // 四舍五入保留两位小数System.out.println("四舍五入取整:(3.856)=" + ne ...
- poj1102
模拟 #include <iostream> #include <string> using namespace std; ][][] = { { ' ', '-', ' ', ...
- mariadb/mysql使用Navicat连接报错
[问题1] 使用Navicat连接服务器的mariadb/mysql时报错 access denied for user root@192.168.xx.xx(using password:yes) ...
- Flask:使用Eclipse+PyDev插件编辑基于package的项目
Windows 10家庭中文版,Python 3.6.4,Flask 1.0.2,Eclipse Oxygen.1a Release (4.7.1a),PyDev 6.3.2 本文记录了 使用Ecli ...
- Python版飞机大战
前面学了java用java写了飞机大战这次学完python基础后写了个python版的飞机大战,有兴趣的可以看下. 父类是飞行物类是所有对象的父类,setting里面是需要加载的图片,你可以换称自己的 ...