swift:自定义UICollectionViewFlowLayout
新型的须求中,要求贯彻一个显得国粹上新的视图,显示方式是点击一个UITableView的cell,在cell拉出一个空白的“抽屉”视图,“抽屉”中横向显示可滚动的多少个宝贝的图文视图,于是很当然地想到用UICollectionView来贯彻。后来那一个需求被砍掉了(orz),可是UICollectionView是一个很有意思很灵巧的视图,类似Android的GridView,不过比之效果更强硬,它可以具体到每一个item的定制,完全取决于UICollectionViewLayout的落到实处。
行文目的
UICollectionView是ios中一个可怜强大的控件,利用它可以极度不难的贯彻部分很为难的效能。UICollectionView的效率又凭借于UICollectionViewLayout要么它的子类UICollectionViewFlowLayout。而关于自定义UICollectionViewFlowLayout网上介绍的可比少。出于这一目的,写下那边文章,希望可以接济初学者(我也是)已毕部分简易的流水布局功效。上面的示范就是本篇小说的对象。最后版代码和具有图片素材(图片名和档次中有点不平等)已经上传至Github,大家可以下载学习。
answer huang的译文中如此表明UICollectionView:
几个不难的概念
- UICollectionViewLayout与UICollectionViewFlowLayout
UICollectionView的浮现效果大概任何由UICollectionViewLayout担当(甚至是cell的深浅)。所以,一般开发中所说的自定义UICollectionView也就是自定义UICollectionViewLayout。而UICollectionViewFlowLayout是继续自UICollectionViewLayout的,由苹果官方达成的湍流布局效率。就算想自己完成部分水流布局作用可以继续自最原始UICollectionViewLayout从头写,也得以继承自UICollectionViewFlowLayout拓展改动。文本是继承自UICollectionViewFlowLayt*
- UICollectionViewLayoutAttributes
其次点就说了UICollectionView的来得效果大概一切由UICollectionViewLayout负责,而实在存储着每一个cell的岗位、大小等质量的是UICollectionViewLayoutAttributes。每一个cell对应着一个属于自己的UICollectionViewLayoutAttributes,而UICollectionViewLayout好在利用UICollectionViewLayoutAttributes里存在的音信对每一个cel举办布局。
- 流水布局
所谓流水布局就是:就是cell以一定的法则举办就像流水一般的有规律的一个跟着一个的排列。�最经典的水流布局便是九宫格布局,绝大部分的图形拔取器也是流水布局。
UITableView和UICollectionView都是由data-source和delegate驱动的。他们为其出示的子视图集扮演为愚笨的器皿(dumb
containers),对她们诚实的情节(contents)毫不知情。
预备干活
- xcode7.0
- swift2.0
- 协调本身提供的材料并在控制器中添加如下代码
class ViewController: UIViewController,UICollectionViewDelegate, UICollectionViewDataSource {
lazy var imageArray: [String] = {
var array: [String] = []
for i in 1...20 {
array.append("\(i)-1")
}
return array
}()
override func viewDidLoad() {
super.viewDidLoad()
let collectionView = UICollectionView(frame: CGRectMake(0, 100, self.view.bounds.width, 200), collectionViewLayout: UICollectionViewFlowLayout())
collectionView.backgroundColor = UIColor.blackColor()
collectionView.dataSource = self
collectionView.delegate = self
collectionView.registerClass(ImageTextCell.self, forCellWithReuseIdentifier: "ImageTextCell")
self.view.addSubview(collectionView)
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.imageArray.count;
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("ImageTextCell", forIndexPath: indexPath) as! ImageTextCell
cell.imageStr = self.imageArray[indexPath.item]
return cell
}
}
//这里是自定义cell的代码
class ImageTextCell: UICollectionViewCell {
var imageView: UIImageView?
var imageStr: NSString? {
didSet {
self.imageView!.image = UIImage(named: self.imageStr as! String)
}
}
override init(frame: CGRect) {
super.init(frame: frame)
self.imageView = UIImageView()
self.addSubview(self.imageView!)
}
override func layoutSubviews() {
super.layoutSubviews()
self.imageView?.frame = self.bounds
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
功用应该是这么的
UICollectionView进一步抽象了。它将其子视图的岗位,大小和外观的控制权委托给一个独立的布局对象。通过提供一个自定义布局对象,你大约可以完成任何你能设想到的布局。布局继承自UICollectionViewLayout那一个抽象基类。iOS6中以UICollectionViewFlowLayout类的格局提议了一个切实可行的布局达成。
编码
关于UICollectionView,其他的同事早就介绍过啦,可以看那里
水平排列
始建一个名为LineLayout.swift的文本(继承自UICollectionViewFlowLayout)。添加如下几行代码
var itemW: CGFloat = 100
var itemH: CGFloat = 100
override init() {
super.init()
//设置每一个元素的大小
self.itemSize = CGSizeMake(itemW, itemH)
//设置滚动方向
self.scrollDirection = .Horizontal
//设置间距
self.minimumLineSpacing = 0.7 * itemW
}
//苹果推荐,对一些布局的准备操作放在这里
override func prepareLayout() {
//设置边距(让第一张图片与最后一张图片出现在最中央)ps:这里可以进行优化
let inset = (self.collectionView?.bounds.width ?? 0) * 0.5 - self.itemSize.width * 0.5
self.sectionInset = UIEdgeInsetsMake(0, inset, 0, inset)
}
功能就成了那样
俺们写一个概括的小demo,效果类似那样
UICollectionViewFlowLayout
shouldInvalidateLayoutForBoundsChange方法与layoutAttributesForElementsInRect方法关系
标题所写出的是越发要害的两措施,先看本身添加的如下测试代码
/**
返回true只要显示的边界发生改变就重新布局:(默认是false)
内部会重新调用prepareLayout和调用
layoutAttributesForElementsInRect方法获得部分cell的布局属性
*/
override func shouldInvalidateLayoutForBoundsChange(newBounds: CGRect) -> Bool {
print(newBounds)
return true
}
/**
用来计算出rect这个范围内所有cell的UICollectionViewLayoutAttributes,
并返回。
*/
override func layoutAttributesForElementsInRect(rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
print("layoutAttributesForElementsInRect==\(rect)")
let ret = super.layoutAttributesForElementsInRect(rect)
// print(ret?.count)
return ret
}
为通晓释,我添加了多少个打印语句,在shouldInvalidateLayoutForBoundsChange再次来到值设置为true后,会发现layoutAttributesForElementsInRect艺术调用至极往往,大概是每滑动一点就会调用一遍。观看打印新闻可以发现许多秘密。
- 启航程序有如下打印
layoutAttributesForElementsInRect==(0.0, 0.0, 568.0, 568.0)
恍如看不太懂,没事,尝试滑动。
- 滑动
(0.5, 0.0, 320.0, 200.0) //这个是shouldInvalidateLayoutForBoundsChange方法的打印的newBounds
layoutAttributesForElementsInRect==(0.0, 0.0, 568.0, 568.0)//这个是layoutAttributesForElementsInRect打印的rect
(1.5, 0.0, 320.0, 200.0)
layoutAttributesForElementsInRect==(0.0, 0.0, 568.0, 568.0)
(3.5, 0.0, 320.0, 200.0)
layoutAttributesForElementsInRect==(0.0, 0.0, 568.0, 568.0)
...
简单察觉,shouldInvalidateLayoutForBoundsChange的参数newBounds的情趣是UICollectionView的可知矩形。什么叫可知矩阵?,因为UICollectionView也是UIScrollView的子类,所以它真的的“内容”远远不止大家屏幕上来看的那么多(那里不再话时间持续解释可知矩阵)。那好像layoutAttributesForElementsInRect打印出来的事物没有吗变化是怎么回事?不急继续滑动。
- 解密
持续滑动后有这一个信息,经过删除一些无用音信,呈现如下。(注意看有注释的行)
...
(248.0, 0.0, 320.0, 200.0)
layoutAttributesForElementsInRect==(0.0, 0.0, 568.0, 568.0)
(249.0, 0.0, 320.0, 200.0) //这里是可见矩阵
layoutAttributesForElementsInRect==(0.0, 0.0, 1136.0, 568.0) //这里变化了1136.0是568.0的2倍(1136代表的是宽度的意思应该知道不需要解释吧)
(250.0, 0.0, 320.0, 200.0)
layoutAttributesForElementsInRect==(0.0, 0.0, 1136.0, 568.0)
...
(567.5, 0.0, 320.0, 200.0)
layoutAttributesForElementsInRect==(0.0, 0.0, 1136.0, 568.0)
(568.5, 0.0, 320.0, 200.0)//这里是可见矩阵
layoutAttributesForElementsInRect==(568.0, 0.0, 568.0, 568.0) // 这里又变化了,x变成了568,宽度变成了568
(571.0, 0.0, 320.0, 200.0)
layoutAttributesForElementsInRect==(568.0, 0.0, 568.0, 568.0)
...
(815.0, 0.0, 320.0, 200.0)
layoutAttributesForElementsInRect==(568.0, 0.0, 568.0, 568.0)
(817.0, 0.0, 320.0, 200.0)
layoutAttributesForElementsInRect==(568.0, 0.0, 1136.0, 568.0) //还有这里
...
(1135.0, 0.0, 320.0, 200.0)
layoutAttributesForElementsInRect==(568.0, 0.0, 1136.0, 568.0)
(1136.0, 0.0, 320.0, 200.0)
layoutAttributesForElementsInRect==(1136.0, 0.0, 568.0, 568.0) //还有这里
地点的的数码彰显实在已经丰盛解释一切了。读到那里,推荐你协调去找找规律,通过协调意识的奥秘相相比较直接看本身写出答案有含义的多!上面这张图例已经证实了所有
有关何以会是568的翻番。。因为我是用的5s模拟器。你换成4s就成为480了。至于那样设计的说辞,我可疑是为着便于举行界定的规定。
那是最简便易行的水流布局:UICollectionViewFlowLayout。类如其义,它提供一个水流布局,item(类似UITableView中的cell)会排列在上一个item的右手,假诺屏幕空间不够,它会活动排到下一行,和流水一样。
缩放效果
精通了下边shouldInvalidateLayoutForBoundsChange方法与layoutAttributesForElementsInRect方法关系后,可以持续举行编码了。因为根本的内容早已讲解为止,剩下的就只是一对卡通的揣测,所以不再继续助教,间接贴出代码。
class LineLayout: UICollectionViewFlowLayout {
var itemW: CGFloat = 100
var itemH: CGFloat = 100
lazy var inset: CGFloat = {
//这样设置,inset就只会被计算一次,减少了prepareLayout的计算步骤
return (self.collectionView?.bounds.width ?? 0) * 0.5 - self.itemSize.width * 0.5
}()
override init() {
super.init()
//设置每一个元素的大小
self.itemSize = CGSizeMake(itemW, itemH)
//设置滚动方向
self.scrollDirection = .Horizontal
//设置间距
self.minimumLineSpacing = 0.7 * itemW
}
//苹果推荐,对一些布局的准备操作放在这里
override func prepareLayout() {
//设置边距(让第一张图片与最后一张图片出现在最中央)
self.sectionInset = UIEdgeInsetsMake(0, inset, 0, inset)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
/**
返回true只要显示的边界发生改变就重新布局:(默认是false)
内部会重新调用prepareLayout和调用
layoutAttributesForElementsInRect方法获得部分cell的布局属性
*/
override func shouldInvalidateLayoutForBoundsChange(newBounds: CGRect) -> Bool {
return true
}
/**
用来计算出rect这个范围内所有cell的UICollectionViewLayoutAttributes,
并返回。
*/
override func layoutAttributesForElementsInRect(rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
//取出rect范围内所有的UICollectionViewLayoutAttributes,然而
//我们并不关心这个范围内所有的cell的布局,我们做动画是做给人看的,
//所以我们只需要取出屏幕上可见的那些cell的rect即可
let array = super.layoutAttributesForElementsInRect(rect)
//可见矩阵
let visiableRect = CGRectMake(self.collectionView!.contentOffset.x, self.collectionView!.contentOffset.y, self.collectionView!.frame.width, self.collectionView!.frame.height)
//接下来的计算是为了动画效果
let maxCenterMargin = self.collectionView!.bounds.width * 0.5 + itemW * 0.5;
//获得collectionVIew中央的X值(即显示在屏幕中央的X)
let centerX = self.collectionView!.contentOffset.x + self.collectionView!.frame.size.width * 0.5;
for attributes in array! {
//如果不在屏幕上,直接跳过
if !CGRectIntersectsRect(visiableRect, attributes.frame) {continue}
let scale = 1 + (0.8 - abs(centerX - attributes.center.x) / maxCenterMargin)
attributes.transform = CGAffineTransformMakeScale(scale, scale)
}
return array
}
/**
用来设置collectionView停止滚动那一刻的位置
- parameter proposedContentOffset: 原本collectionView停止滚动那一刻的位置
- parameter velocity: 滚动速度
- returns: 最终停留的位置
*/
override func targetContentOffsetForProposedContentOffset(proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint {
//实现这个方法的目的是:当停止滑动,时刻有一张图片是位于屏幕最中央的。
let lastRect = CGRectMake(proposedContentOffset.x, proposedContentOffset.y, self.collectionView!.frame.width, self.collectionView!.frame.height)
//获得collectionVIew中央的X值(即显示在屏幕中央的X)
let centerX = proposedContentOffset.x + self.collectionView!.frame.width * 0.5;
//这个范围内所有的属性
let array = self.layoutAttributesForElementsInRect(lastRect)
//需要移动的距离
var adjustOffsetX = CGFloat(MAXFLOAT);
for attri in array! {
if abs(attri.center.x - centerX) < abs(adjustOffsetX) {
adjustOffsetX = attri.center.x - centerX;
}
}
return CGPointMake(proposedContentOffset.x + adjustOffsetX, proposedContentOffset.y)
}
}
万一在控制器中加入上面七个艺术,在您点击控制器,或者点击某个cell会有很炫的动画暴发,那都是苹果帮我们做好的。
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
self.imageArray.removeAtIndex(indexPath.item)
collectionView.deleteItemsAtIndexPaths([indexPath])
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
if self.collectionView!.collectionViewLayout.isKindOfClass(LineLayout.self) {
self.collectionView!.setCollectionViewLayout(UICollectionViewFlowLayout(), animated: true)
}else {
self.collectionView!.setCollectionViewLayout(LineLayout(), animated: true)
}
}
代码如下:
总结
本篇作品记录了本人在自定义UICollectionViewFlowLayout进程中遇到的一部分标题和缓解措施(其实有一部分坑爹的题材自己从没列出,怕误导大家)。上边的全部都是基于UICollectionViewFlowLayout进展的更动。而自我在GitHub上边上传的也有一份继承自UICollectionViewLayout的非流水布局。效果如下,因为原理性的东西都大约,就不再进行分析(代码也有注释)。感兴趣的可以这Github下面下载。尽管小说中有如何错误或者更好的法子、指出等等,感谢您的提出。大家联合学习!O(∩_∩)O!
-
(UICollectionView *)collectionView
{
if (!_collectionView) {
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout
alloc] init];
self.currentLayout = layout;
_collectionView = [[UICollectionView alloc]
initWithFrame:CGRectMake(0, 150, [UIScreen
mainScreen].bounds.size.width, 240)
collectionViewLayout:layout];
_collectionView.delegate = self;
_collectionView.dataSource = self;
[_collectionView registerClass:[ZQCollectionViewCell class]
forCellWithReuseIdentifier:@”cell”];
}return _collectionView;
}
后记
自家不会报告你,介绍UICollectionView的自定义布局那篇文章,是本人下一个尝试的前传。然则近来被老师强迫帮她们去写文档,估量过程得急性。
俺们后日想实现一个如此的效应:
当左右拖动item的时候,靠近屏幕大旨item放大,远离中央的item减弱
左右滑行的时候,甘休下来的item的主旨永远和屏幕要旨对齐
功能如图:
linear
第一,大家须求自定义UICollectionViewLayout。由于必要效果依旧保持流水特性,我们选拔继承UICollectionViewFlowLayout。须求重写的法子如下:
- (void)prepareLayout:该办法是历次布局时部分准备工作,可以在这里做一些开首化的操作,记得调用super完结!
- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds:当布局的界线发送改变的时候,会询问该方法是或不是再一次布局
- (NSArray
*)layoutAttributesForElementsInRect:(CGRect)rect:返回可知的rect中拥有的Elements的布局属性(UICollectionViewLayoutAttributes)。在UICollectionViewLayoutAttributes可安装item的size、center、transform等等属性,来规范定制item的地方和形变.UICollectionViewFlowLayout对该措施有一个默认已毕,可使item流水式排列。而UICollectionViewLayout则一心是空已毕,必要大家团结一心计算 - (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset
withScrollingVelocity:(CGPoint)velocity:当item被滑动自行为止时,大家可以按照这一个形式设定item停在大家期望的地点
代码如下:
-
(void)prepareLayout
{
[super prepareLayout];
// 每个item的size
self.itemSize = CGSizeMake(ITEM_SIZE, ITEM_SIZE);
// 最小间距
self.minimumLineSpacing = 50;
// 横向滚动
self.scrollDirection = UICollectionViewScrollDirectionHorizontal;
// 内间距
self.sectionInset = UIEdgeInsetsMake(90,
(self.collectionView.bounds.size.width – ITEM_SIZE) * 0.5, 40,
150);
} -
(BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds
{
return YES;
} -
(CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset
withScrollingVelocity:(CGPoint)velocity
{
// 当前屏幕的rect
CGRect visiableRect = {proposedContentOffset,
self.collectionView.bounds.size};
CGFloat currentCenterX = proposedContentOffset.x +
self.collectionView.bounds.size.width * 0.5;
// 调用super达成可以获获得当下rect中颇具item的布局属性
NSArray *attributesArray = [super
layoutAttributesForElementsInRect:visiableRect];
CGFloat adjustDistance = MAXFLOAT;
// 总计距离大旨点近期的item,来算偏移量
for (UICollectionViewLayoutAttributes *attributes in
attributesArray) {
if (CGRectIntersectsRect(attributes.frame, visiableRect)) {//
在屏幕内
CGFloat x = attributes.center.x;
if (ABS(x – currentCenterX) < ABS(adjustDistance)) {
adjustDistance = x – currentCenterX;
}
}
}return CGPointMake(proposedContentOffset.x + adjustDistance,
proposedContentOffset.y);
} -
(NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
CGRect visiableRect = {self.collectionView.contentOffset,
self.collectionView.bounds.size};
CGFloat currentCenterX = self.collectionView.contentOffset.x +
self.collectionView.bounds.size.width * 0.5;
NSArray *attributesArray = [super
layoutAttributesForElementsInRect:visiableRect];
for (UICollectionViewLayoutAttributes *attributes in
attributesArray) {
if (CGRectIntersectsRect(attributes.frame, visiableRect)) {//
在显示屏内
CGFloat itemCenterX = attributes.center.x;
// 设定一个推广的全面,公式大家可以团结来定,效果类似就足以
CGFloat scale = 1 + SCALE_FACTOR * (1 – (ABS(itemCenterX –
currentCenterX) / SCALE_BIG_DISTANCE));
attributes.transform3D = CATransform3DMakeScale(scale, scale,
1.0);
}
}
return attributesArray;
}
如上是继承UICollectionViewFlowLayout的布局,借使大家想做四回更深层次的定制,大家得以一贯继承UICollectionViewLayout来完全自定义布局,要重写的措施和UICollectionViewFlowLayout类似,只是大家需求协调来贯彻这几个主意:
- (NSArray
*)layoutAttributesForElementsInRect:(CGRect)rect:必要团结新建UICollectionViewLayoutAttributes,也足以通过上边的办法2完了 - (UICollectionViewLayoutAttributes
*)layoutAttributesForItemAtIndexPath:(NSIndexPath
*)indexPath:该情势确定当前indexPath下的item的布局属性
代码如下:
-
(void)prepareLayout
{
[super prepareLayout];
} -
(BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds
{
return YES;
} -
(NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
NSInteger count = [self.collectionView
numberOfItemsInSection:0];
NSMutableArray *attributesArray = [NSMutableArray array];
for (NSInteger i = 0; i < count; ++i) {
UICollectionViewLayoutAttributes *attributes = [self
layoutAttributesForItemAtIndexPath:[NSIndexPath indexPathForItem:i
inSection:0]];
[attributesArray addObject:attributes];
}
return attributesArray;
} -
(UICollectionViewLayoutAttributes
*)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
{
NSInteger count = [self.collectionView
numberOfItemsInSection:0];
CGPoint currentCenter =
CGPointMake(self.collectionView.contentOffset.x +
self.collectionView.bounds.size.width * 0.5,
self.collectionView.bounds.size.height * 0.5);
UICollectionViewLayoutAttributes *attributes =
[UICollectionViewLayoutAttributes
layoutAttributesForCellWithIndexPath:indexPath];
attributes.size = CGSizeMake(ITEM_SIZE, ITEM_SIZE);CGFloat angelDelta = M_PI * 2 / count;
CGFloat angel = M_PI_2 – angelDelta * indexPath.row;
attributes.center = CGPointMake(currentCenter.x + CIRCLE_RADIUS *
cosf(angel), currentCenter.y + CIRCLE_RADIUS * sinf(angel));
return attributes;
}
如上可完毕一个环形(circle)布局,
demo中还添加了点击item就把该item删除的事件
circel
还能做一个像样蜂巢的布局:
-
(CGSize)collectionViewContentSize
{
NSInteger count = [self.collectionView
numberOfItemsInSection:0];
return CGSizeMake(0, (count / COL)* count);
} -
(UICollectionViewLayoutAttributes
*)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewLayoutAttributes *attributes =
[UICollectionViewLayoutAttributes
layoutAttributesForCellWithIndexPath:indexPath];UICollectionView *collection = self.collectionView;
float x = (SIZE + self.margin) * (indexPath.item % COL + 1) *
0.75 + 40;
float y = (SIZE + self.margin) * (indexPath.item / COL + 0.5) *
cos(M_PI * 30.0f / 180.0f) + 20;
if (indexPath.item % 2 == 1) {
y += (SIZE + self.margin) * 0.5 * cosf(M_PI * 30.0f / 180.0f);
}attributes.center = CGPointMake(x + collection.contentOffset.x, y +
collection.contentOffset.y);
attributes.size = CGSizeMake(SIZE, SIZE * cos(M_PI * 30.0f /
180.0f));return attributes;
}
-(NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
NSArray *arr = [super layoutAttributesForElementsInRect:rect];
if ([arr count] > 0) {
return arr;
}
NSMutableArray *attributes = [NSMutableArray array];
for (NSInteger i = 0 ; i < [self.collectionView
numberOfItemsInSection:0 ]; i++) {
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i
inSection:0];
[attributes addObject:[self
layoutAttributesForItemAtIndexPath:indexPath]];
}
return attributes;
}
其中cell的样式:
- (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
self.backgroundColor = ZQRandomColor;
CGFloat longSide = SIZE * 0.5 * cosf(M_PI * 30 / 180);
CGFloat shortSide = SIZE * 0.5 * sinf(M_PI * 30 / 180);
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(0, longSide)];
[path addLineToPoint:CGPointMake(shortSide, 0)];
[path addLineToPoint:CGPointMake(shortSide + SIZE * 0.5, 0)];
[path addLineToPoint:CGPointMake(SIZE, longSide)];
[path addLineToPoint:CGPointMake(shortSide + SIZE * 0.5, longSide * 2)];
[path addLineToPoint:CGPointMake(shortSide, longSide * 2)];
[path closePath];
CAShapeLayer *maskLayer = [CAShapeLayer layer];
maskLayer.path = [path CGPath];
self.layer.mask = maskLayer;
}
return self;
}
效果如图:
honeycomb