#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:0];
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=0; i<cellCount; i++)
{
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0];

UICollectionViewLayoutAttributes *attributes = [self layoutAttributesForItemAtIndexPath:indexPath];

[array addObject:attributes];
}

//add first supplementaryView
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:0];
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(20, 20);
attributes.center = CGPointMake(cvCenter.x + radius * cosf(2 * indexPath.item * M_PI / cellCount),
cvCenter.y + radius * sinf(2 * indexPath.item * M_PI / cellCount));

return attributes;
}

- (UICollectionViewLayoutAttributes *)layoutAttributesForSupplementaryViewOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForSupplementaryViewOfKind:elementKind withIndexPath:indexPath];

attributes.size = CGSizeMake(260, 40);
if([elementKind isEqual:@"FirstSupplementary"])
{
attributes.center = CGPointMake(cvSize.width/2, 40);
}
else
{
attributes.center = CGPointMake(cvSize.width/2, cvSize.height-40);
}

return attributes;
}

- (UICollectionViewLayoutAttributes *)layoutAttributesForDecorationViewOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForDecorationViewOfKind:elementKind withIndexPath:indexPath];

attributes.size = CGSizeMake(140, 40);
attributes.center = CGPointMake(cvSize.width/2, cvSize.height/2);

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(10,10),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

自定义UICollectionLayout的更多相关文章

  1. 自定义UICollectionLayout布局 —— UIKit之学习UICollectionView记录一《瀑布流》

    一.思路 思路一:比较每一行所有列的cell的高度,从上到下(也就是从第一行开始),从最短的开始计算,(记录下b的高度和索引,从开始计算,依次类推) 思路二:设置上.下.左.右间距和行间距.列间距及列 ...

  2. 自定义 ---UICollectionViewLayout-正N变形居中布局

    1. 自定义UICollectionLayout ---- 正三角形居中布局 支持多个图形的自动布局 2. 自定义UICollectionLayout ---- 正方形居中布局 滚动展示的区域 3.  ...

  3. 关于Unity3D自定义编辑器的学习

    被人物编辑器折腾了一个月,最终还是交了点成品上去(还要很多优化都还么做).  刚接手这项工作时觉得没概念,没想法,不知道.后来就去看<<Unity5.X从入门到精通>>中有关于 ...

  4. 一起学微软Power BI系列-使用技巧(5)自定义PowerBI时间日期表

    1.日期函数表作用 经常使用Excel或者PowerBI,Power Pivot做报表,时间日期是一个重要的纬度,加上做一些钻取,时间日期函数表不可避免.所以今天就给大家分享一个自定义的做日期表的方法 ...

  5. JavaScript自定义浏览器滚动条兼容IE、 火狐和chrome

    今天为大家分享一下我自己制作的浏览器滚动条,我们知道用css来自定义滚动条也是挺好的方式,css虽然能够改变chrome浏览器的滚动条样式可以自定义,css也能够改变IE浏览器滚动条的颜色.但是css ...

  6. ASP.NET Aries 入门开发教程8:树型列表及自定义右键菜单

    前言: 前面几篇重点都在讲普通列表的相关操作. 本篇主要讲树型列表的操作. 框架在设计时,已经把树型列表和普通列表全面统一了操作,用法几乎是一致的. 下面介绍一些差距化的内容: 1:树型列表绑定: v ...

  7. ASP.NET Aries 入门开发教程5:自定义列表页工具栏区

    前言: 抓紧时间,继续写教程,因为发现用户期待的内容,都在业务处理那一块. 不得不继续勤劳了. 这节主要介绍工具栏区的玩法. 工具栏的默认介绍: 工具栏默认包括5个按钮,根据不同的权限决定显示: 添加 ...

  8. UWP中实现自定义标题栏

    UWP中实现自定义标题栏 0x00 起因 在UWP开发中,有时候我们希望实现自定义标题栏,例如在标题栏中加入搜索框.按钮之类的控件.搜了下资料居然在一个日文网站找到了一篇介绍这个主题的文章: http ...

  9. JavaScript 自定义对象

    在Js中,除了Array.Date.Number等内置对象外,开发者可以通过Js代码创建自己的对象. 目录 1. 对象特性:描述对象的特性 2. 创建对象方式:对象直接量.new 构造函数.Objec ...

随机推荐

  1. Android 内存泄漏优化总结

    1,验证是否为汉字 ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 3 ...

  2. Selenium 详解xpath定位

    xpath定位在业界被戏称为元素定位的"屠龙宝刀",宝刀在手,武林我有.现在我们就来详解xpath定位方法. 一.xpath通过元素属性定位 xpath可以通过元素的属性来定位,如 ...

  3. EF 视图查询坑

    EF 视图在查询的时候如果主键一样则默认的数据都是第一条查询的数据

  4. 微信小程序 API 路由

    路由:由于页面的跳转: wx.switchTab() 跳转到 tabBar 页面,并关闭掉其他所有非 tabBar 页面: 参数:为对象, 对象的属性: url:需要跳转的 tabBar 的页面路径( ...

  5. 用ps 查看线程状态

    ps -eLo pid,tid,class,rtprio,ni,pri,psr,pcpu,pmem,stat,wchan:30,comm 线程相关选项: THREAD DISPLAY H Show t ...

  6. freetype相关总结

    FreeType-2.7 API : https://www.freetype.org/freetype2/docs/reference/ft2-basic_types.html ---------- ...

  7. ES6正则拓展

    字符串的正则方法 字符串对象共有 4 个方法,可以使用正则表达式:match().replace().search()和split(). ES6 将这 4 个方法,在语言内部全部调用RegExp的实例 ...

  8. JQuery插件 aos.js

    简介: aos.js是一款效果超赞的页面滚动元素动画jQuery动画库插件.该动画库可以在页面滚动时提供28种不同的元素动画效果,以及多种easing效果.在页面往回滚动时,元素会恢复到原来的状态. ...

  9. for...in 、Object.keys 、 Object.getOwnPropertyNames

    个人总结: 1.for...in 遍历的是对象的可枚举,非Symbol属性(包括自身和原型上的) 2.Object.keys 返回一个数组,是对象自身的可枚举属性 (非Symbol) 3.Object ...

  10. JavaScript中JSON的序列化和解析

    1.序列化:JSON对象----->JSON格式字符串 ①方法: JSON.stringify() ②示例程序: var jsonString = JSON.stringify(obj); al ...