UICollectionView

引用自:http://www.jianshu.com/p/c59a5c92f859

一、UICollectionVIew基础

第一步:创建布局对象:

如果使用系统的布局类,我们通常是使用其UICollectionViewFlowLayout子类,通过这个子类来创建我们的布局对象。实例:UICollectionVIewFlowLayout *flowLayout = [UICollectionVIewFlowLayout new];

通过这个实例化的对象提供了一些基本的属性,用于帮助我们控制布局的方式,当然这个类也有其自身的协议,通过签署协议可以实现协议中的一些方法,这些方法可以帮助我们实现更加完善的布局。协议名字叫做:“UICollectionVIewDelegateFlowLayout”,这个协议也是实现基本CollectionVIew的三个协议中必须用到的,其他另外两个协议分别是:UICollectionViewDataSource(数据源)、UICollectionViewDelegate。

下面简单介绍一些关于这个类对象用于实现布局的属性有哪些:

@property(nonatomic)CGFloatminimumLineSpacing;// 这个用于指定每个Item的行间距,默认间距是10.

@property(nonatomic)CGFloatminimumInteritemSpacing;//用于指定每个单元的列间距。

@property(nonatomic)CGSizeitemSize;//指定每个cell的size.

@property(nonatomic)CGSizeestimatedItemSizeNS_AVAILABLE_IOS(8_0);//defaults to CGSizeZero - setting a non-zero size enables cells that self-size via -preferredLayoutAttributesFittingAttributes:

@property(nonatomic)UICollectionViewScrollDirectionscrollDirection;// default is UICollectionViewScrollDirectionVertical

@property(nonatomic)CGSizeheaderReferenceSize;

@property(nonatomic)CGSizefooterReferenceSize;//头部增添视图的size

@property(nonatomic)UIEdgeInsetssectionInset;//设置分区的内边距距离上左下右的距离,所以这个参数有四个参数。

// Set these properties to YES to get headers that pin to the top of the screen and footers that pin to the bottom while scrolling (similar to UITableView).

@property(nonatomic)BOOLsectionHeadersPinToVisibleBoundsNS_AVAILABLE_IOS(9_0);

@property(nonatomic)BOOLsectionFootersPinToVisibleBoundsNS_AVAILABLE_IOS(9_0);c//用于控制是否在当前窗口显示下一个分区的尾增添

第二步:通过布局对象创建UICollectionView,并设置相关属性,重点是给代理属性给定对象。

初始化UICollectionVIew的方法:

Frame:指定UICollectionView的Frame

collectionViewLayout:指定UICollectView的布局对象。

- (instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout*)layoutNS_DESIGNATED_INITIALIZER;

第三步:设置好各个重用标识

这里就不多说了,在代码的全局位置指定三个全局字符常量。

第四步:使用重用标识注册相关的重用池。

cell的重用池的注册方法:

Class:指定用哪个类作为cell,所以我们可以通过新建继承自UICollectionViewLayout的类来自定义cell.

- (void)registerClass:(nullableClass)cellClass forCellWithReuseIdentifier:(NSString*)identifier;

补充视图重用池的注册方法:

forSupplementaryViewOfKind:指定补充视图的类型

withReuseIdentifier:指定一个重用标识符

- (void)registerClass:(nullableClass)viewClass forSupplementaryViewOfKind:(NSString*)elementKind withReuseIdentifier:(NSString*)identifier;

第五步:实现UICollectionViewDataSource的几个代理方法(这里只提几个常用的)

#pragma mark ---- UICollectionViewDataSource

//  指定在一个CollectionView上分区的数量。

- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView

{

return 1;

}

// 指定在每个分区上Item的数量。

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

{

return _section0Array.count;

}

// 从重用池中取出UICollectionVIew的celle来给每个Item赋值。

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

{

UICollectionViewCell *cell = [_collectionView dequeueReusableCellWithReuseIdentifier:cellId forIndexPath:indexPath];

cell.backgroundColor = [UIColor purpleColor];

return cell;

}

// 和UITableView类似,UICollectionView也可设置段头段尾

这个方法中的参数分别是:

collectionView:这个就不解释了,每个协议中必须传入的跟类。

viewForSupplementaryElementOfKind:根据传入的Kind值来判断到底添加的是那种类型的视图。

atIndexPath:这个参数通过传值来确定到底给那个分区补充视图。

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

{

if([kind isEqualToString:UICollectionElementKindSectionHeader])

{

UICollectionReusableView *headerView = [_collectionView dequeueReusableSupplementaryViewOfKind:kind withReuseIdentifier:headerId forIndexPath:indexPath];

if(headerView == nil)

{

headerView = [[UICollectionReusableView alloc] init];

}

headerView.backgroundColor = [UIColor grayColor];

return headerView;

}

else if([kind isEqualToString:UICollectionElementKindSectionFooter])

{

UICollectionReusableView *footerView = [_collectionView dequeueReusableSupplementaryViewOfKind:kind withReuseIdentifier:footerId forIndexPath:indexPath];

if(footerView == nil)

{

footerView = [[UICollectionReusableView alloc] init];

}

footerView.backgroundColor = [UIColor lightGrayColor];

return footerView;

}

return nil;

}

// 暂时理解为:能够移动的Item,有待验证。

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

{

return YES;

}

//  暂时理解为:给能够移动的Item指定移动路径,有待验证。

moveItemAtIndexPath:能够一定的Item路径。

toIndexPath:移动到的目标路径。

- (void)collectionView:(UICollectionView *)collectionView moveItemAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath*)destinationIndexPath

{

}

第六步:实现UICollectionViewDelegateFlowLayout协议方法(这里的很多方法用属性的点语法同样可以实现,建议使用点语法。)

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath

{

return (CGSize){cellWidth,cellWidth};

}

- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section

{

return UIEdgeInsetsMake(5, 5, 5, 5);

}

- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section

{

return 5.f;

}

- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section

{

return 5.f;

}

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section

{

return (CGSize){ScreenWidth,44};

}

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForFooterInSection:(NSInteger)section

{

return (CGSize){ScreenWidth,22};

}

第七步:实现UICollectionViewDelegate方法

// 指定那些Item需要高亮显示

- (BOOL)collectionView:(UICollectionView *)collectionView shouldHighlightItemAtIndexPath:(NSIndexPath *)indexPath

{

return YES;

}

// 点击高亮

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

{

UICollectionViewCell *cell = [collectionView cellForItemAtIndexPath:indexPath];

cell.backgroundColor = [UIColor greenColor];

}

// 选中某item

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

{

}

// 长按某item,弹出copy和paste的菜单

- (BOOL)collectionView:(UICollectionView *)collectionView shouldShowMenuForItemAtIndexPath:(NSIndexPath *)indexPath

{

return YES;

}

// 使copy和paste有效

- (BOOL)collectionView:(UICollectionView *)collectionView canPerformAction:(SEL)action forItemAtIndexPath:(NSIndexPath *)indexPath withSender:(nullable id)sender

{

if ([NSStringFromSelector(action) isEqualToString:@"copy:"] || [NSStringFromSelector(action) isEqualToString:@"paste:"])

{

return YES;

}

return NO;

}

//

- (void)collectionView:(UICollectionView *)collectionView performAction:(SEL)action forItemAtIndexPath:(NSIndexPath *)indexPath withSender:(nullable id)sender

{

if([NSStringFromSelector(action) isEqualToString:@"copy:"])

{

//        NSLog(@"-------------执行拷贝-------------");

[_collectionView performBatchUpdates:^{

[_section0Array removeObjectAtIndex:indexPath.row];

[_collectionView deleteItemsAtIndexPaths:@[indexPath]];

} completion:nil];

}

else if([NSStringFromSelector(action) isEqualToString:@"paste:"])

{

NSLog(@"-------------执行粘贴-------------");

}

}

二、自定义布局

UICollectionView自定义布局

要自定义UICollectionView布局,就要子类化UICollectionViewLayout,然后重写它的一些方法以达到我们自定义布局的需求。下来我们来看看UICollectionViewLayout类里一些比较重要的方法:

- (void)prepareLayout;为layout显示做准备工作,你可以在该方法里设置一些属性。

- (CGSize)collectionViewContentSize;返回layout的size。

- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect;返回在collectionView的可见范围内(bounds)所有item对应的layoutAttrure对象装成的数组。collectionView的每个item都对应一个专门的UICollectionViewLayoutAttributes类型的对象来表示该item的一些属性,比如bounds,size,transform,alpha等。

- (UICollectionViewLayoutAttributes)layoutAttributesForItemAtIndexPath:(NSIndexPath)indexPath;传入indexPath,返回该indexPath对应的layoutAtture对象。

- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds;当当前layout的布局发生变动时,是否重写加载该layout。默认返回NO,若返回YES,则重新执行这俩方法:

- (void)prepareLayout;

- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect;

- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity;返回layout“最终”的偏移量,何谓“最终”,手指离开屏幕时layout的偏移量不是最终的,因为它有惯性,当它停止时才是“最终”偏移量。

自定义插入删除动画

插入删除的操作

添加在哪触发:

UIBarButtonItem *btnItem = [[UIBarButtonItem alloc] initWithTitle:@"添加"

style:UIBarButtonItemStylePlain

target:self

action:@selector(addItemBtnClick:)];

self.navigationItem.rightBarButtonItem = btnItem;

添加的实现:

// 添加(插入item)

- (void)addItemBtnClick:(UIBarButtonItem *)btnItem

{

[_collectionView performBatchUpdates:^{

// 构造一个indexPath

NSIndexPath *indePath = [NSIndexPath indexPathForItem:_section0Array.count inSection:0];

[_collectionView insertItemsAtIndexPaths:@[indePath]]; // 然后在此indexPath处插入给collectionView插入一个item

[_section0Array addObject:@"x"]; // 保持collectionView的item和数据源一致

} completion:nil];

}

因为是练习Demo,所以暂时把删除的触发源写在了长按某Item弹出菜单的copy按钮里。实际中你可以自定义UICollectionViewCell,添加长按手势,长按抖动出现叉号,然后删除等,随你怎么做。

// copy and paste 的实现

- (void)collectionView:(UICollectionView *)collectionView performAction:(SEL)action forItemAtIndexPath:(NSIndexPath *)indexPath withSender:(nullable id)sender

{

if([NSStringFromSelector(action) isEqualToString:@"copy:"])

{

//        NSLog(@"-------------执行拷贝-------------");

[_collectionView performBatchUpdates:^{

[_section0Array removeObjectAtIndex:indexPath.row];

[_collectionView deleteItemsAtIndexPaths:@[indexPath]];

} completion:nil];

}

else if([NSStringFromSelector(action) isEqualToString:@"paste:"])

{

NSLog(@"-------------执行粘贴-------------");

}

}

自定义转场动画

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,185评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,445评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,684评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,564评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,681评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,874评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,025评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,761评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,217评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,545评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,694评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,351评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,988评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,778评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,007评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,427评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,580评论 2 349

推荐阅读更多精彩内容