├── README.md ├── XLPlainFlowLayout ├── .DS_Store ├── XLPlainFlowLayout.h └── XLPlainFlowLayout.m ├── XLPlainFlowLayoutDemo ├── .DS_Store ├── XLPlainFlowLayout │ ├── XLPlainFlowLayout.h │ └── XLPlainFlowLayout.m ├── XLPlainFlowLayoutDemo.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ ├── xcshareddata │ │ │ └── XLPlainFlowLayoutDemo.xccheckout │ │ └── xcuserdata │ │ │ └── hebe.xcuserdatad │ │ │ └── UserInterfaceState.xcuserstate │ └── xcuserdata │ │ └── hebe.xcuserdatad │ │ └── xcschemes │ │ ├── XLPlainFlowLayoutDemo.xcscheme │ │ └── xcschememanagement.plist ├── XLPlainFlowLayoutDemo │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── Images.xcassets │ │ ├── AppIcon.appiconset │ │ │ └── Contents.json │ │ └── LaunchImage.launchimage │ │ │ └── Contents.json │ ├── Info.plist │ ├── ReusableView.h │ ├── ReusableView.m │ ├── ViewController.h │ ├── ViewController.m │ └── main.m └── XLPlainFlowLayoutDemoTests │ ├── Info.plist │ └── XLPlainFlowLayoutDemoTests.m └── demo.gif /README.md: -------------------------------------------------------------------------------- 1 | # XLPlainFlowLayout 2 | 可以让UICollectionView的header也支持悬停效果,类似于tableView的Plain风格 3 | 4 | 新浪微博:[亮亮亮亮亮靓啊](http://www.weibo.com/zxliang7) 5 | 6 | ![](https://github.com/HebeTienCoder/XLPlainFlowLayout/raw/master/demo.gif) 7 | -------------------------------------------------------------------------------- /XLPlainFlowLayout/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HebeTienCoder/XLPlainFlowLayout/ee440ffb0b31e996f9b2e3dd472ceba5e65d6733/XLPlainFlowLayout/.DS_Store -------------------------------------------------------------------------------- /XLPlainFlowLayout/XLPlainFlowLayout.h: -------------------------------------------------------------------------------- 1 | // 2 | // XLPlainFlowLayout.h 3 | // XLPlainFlowLayout 4 | // 5 | // Created by hebe on 15/7/30. 6 | // Copyright (c) 2015年 ___ZhangXiaoLiang___. All rights reserved. 7 | // 8 | // 工作邮箱E-mail: k52471@126.com 9 | 10 | #import 11 | 12 | @interface XLPlainFlowLayout : UICollectionViewFlowLayout 13 | 14 | @property (nonatomic, assign) CGFloat naviHeight;//默认为64.0, default is 64.0 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /XLPlainFlowLayout/XLPlainFlowLayout.m: -------------------------------------------------------------------------------- 1 | // 2 | // XLPlainFlowLayout.m 3 | // XLPlainFlowLayout 4 | // 5 | // Created by hebe on 15/7/30. 6 | // Copyright (c) 2015年 ___ZhangXiaoLiang___. All rights reserved. 7 | // 8 | // 工作邮箱E-mail: k52471@126.com 9 | 10 | #import "XLPlainFlowLayout.h" 11 | 12 | @implementation XLPlainFlowLayout 13 | 14 | -(instancetype)init 15 | { 16 | self = [super init]; 17 | if (self) 18 | { 19 | _naviHeight = 64.0; 20 | } 21 | return self; 22 | } 23 | 24 | 25 | - (NSArray *) layoutAttributesForElementsInRect:(CGRect)rect 26 | { 27 | //UICollectionViewLayoutAttributes:我称它为collectionView中的item(包括cell和header、footer这些)的《结构信息》 28 | //截取到父类所返回的数组(里面放的是当前屏幕所能展示的item的结构信息),并转化成不可变数组 29 | NSMutableArray *superArray = [[super layoutAttributesForElementsInRect:rect] mutableCopy]; 30 | 31 | //创建存索引的数组,无符号(正整数),无序(不能通过下标取值),不可重复(重复的话会自动过滤) 32 | NSMutableIndexSet *noneHeaderSections = [NSMutableIndexSet indexSet]; 33 | //遍历superArray,得到一个当前屏幕中所有的section数组 34 | for (UICollectionViewLayoutAttributes *attributes in superArray) 35 | { 36 | //如果当前的元素分类是一个cell,将cell所在的分区section加入数组,重复的话会自动过滤 37 | if (attributes.representedElementCategory == UICollectionElementCategoryCell) 38 | { 39 | [noneHeaderSections addIndex:attributes.indexPath.section]; 40 | } 41 | } 42 | 43 | //遍历superArray,将当前屏幕中拥有的header的section从数组中移除,得到一个当前屏幕中没有header的section数组 44 | //正常情况下,随着手指往上移,header脱离屏幕会被系统回收而cell尚在,也会触发该方法 45 | for (UICollectionViewLayoutAttributes *attributes in superArray) { 46 | //如果当前的元素是一个header,将header所在的section从数组中移除 47 | if ([attributes.representedElementKind isEqualToString:UICollectionElementKindSectionHeader]) { 48 | [noneHeaderSections removeIndex:attributes.indexPath.section]; 49 | } 50 | } 51 | 52 | //遍历当前屏幕中没有header的section数组 53 | [noneHeaderSections enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) { 54 | 55 | //取到当前section中第一个item的indexPath 56 | NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:idx]; 57 | //获取当前section在正常情况下已经离开屏幕的header结构信息 58 | UICollectionViewLayoutAttributes *attributes = [self layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionHeader atIndexPath:indexPath]; 59 | 60 | //如果当前分区确实有因为离开屏幕而被系统回收的header 61 | if (attributes) { 62 | //将该header结构信息重新加入到superArray中去 63 | [superArray addObject:attributes]; 64 | } 65 | }]; 66 | 67 | //遍历superArray,改变header结构信息中的参数,使它可以在当前section还没完全离开屏幕的时候一直显示 68 | for (UICollectionViewLayoutAttributes *attributes in superArray) { 69 | 70 | //如果当前item是header 71 | if ([attributes.representedElementKind isEqualToString:UICollectionElementKindSectionHeader]) { 72 | 73 | //得到当前header所在分区的cell的数量 74 | NSInteger numberOfItemsInSection = [self.collectionView numberOfItemsInSection:attributes.indexPath.section]; 75 | //得到第一个item的indexPath 76 | NSIndexPath *firstItemIndexPath = [NSIndexPath indexPathForItem:0 inSection:attributes.indexPath.section]; 77 | //得到最后一个item的indexPath 78 | NSIndexPath *lastItemIndexPath = [NSIndexPath indexPathForItem:MAX(0, numberOfItemsInSection-1) inSection:attributes.indexPath.section]; 79 | //得到第一个item和最后一个item的结构信息 80 | UICollectionViewLayoutAttributes *firstItemAttributes, *lastItemAttributes; 81 | if (numberOfItemsInSection>0) { 82 | //cell有值,则获取第一个cell和最后一个cell的结构信息 83 | firstItemAttributes = [self layoutAttributesForItemAtIndexPath:firstItemIndexPath]; 84 | lastItemAttributes = [self layoutAttributesForItemAtIndexPath:lastItemIndexPath]; 85 | }else{ 86 | //cell没值,就新建一个UICollectionViewLayoutAttributes 87 | firstItemAttributes = [UICollectionViewLayoutAttributes new]; 88 | //然后模拟出在当前分区中的唯一一个cell,cell在header的下面,高度为0,还与header隔着可能存在的sectionInset的top 89 | CGFloat y = CGRectGetMaxY(attributes.frame)+self.sectionInset.top; 90 | firstItemAttributes.frame = CGRectMake(0, y, 0, 0); 91 | //因为只有一个cell,所以最后一个cell等于第一个cell 92 | lastItemAttributes = firstItemAttributes; 93 | } 94 | 95 | //获取当前header的frame 96 | CGRect rect = attributes.frame; 97 | 98 | /** 99 | * 算法 100 | */ 101 | //当前的滑动距离 + 因为导航栏产生的偏移量,默认为64(如果app需求不同,需自己设置) 102 | CGFloat offset = self.collectionView.contentOffset.y + _naviHeight; 103 | //第一个cell的y值 - 当前header的高度 - 可能存在的sectionInset的top 104 | CGFloat headerY = firstItemAttributes.frame.origin.y - rect.size.height - self.sectionInset.top; 105 | 106 | //哪个大取哪个,保证header悬停 107 | //针对当前header基本上都是offset更加大,针对下一个header则会是headerY大,各自处理 108 | CGFloat maxY = MAX(offset,headerY); 109 | 110 | //最后一个cell的y值 + 最后一个cell的高度 + 可能存在的sectionInset的bottom - 当前header的高度 111 | //当当前section的footer或者下一个section的header接触到当前header的底部,计算出的headerMissingY即为有效值 112 | CGFloat headerMissingY = CGRectGetMaxY(lastItemAttributes.frame) + self.sectionInset.bottom - rect.size.height; 113 | 114 | //给rect的y赋新值,因为在最后消失的临界点要跟谁消失,所以取小 115 | rect.origin.y = MIN(maxY,headerMissingY); 116 | //给header的结构信息的frame重新赋值 117 | attributes.frame = rect; 118 | 119 | //如果按照正常情况下,header离开屏幕被系统回收,而header的层次关系又与cell相等,如果不去理会,会出现cell在header上面的情况 120 | //通过打印可以知道cell的层次关系zIndex数值为0,我们可以将header的zIndex设置成1,如果不放心,也可以将它设置成非常大,这里随便填了个7 121 | attributes.zIndex = 7; 122 | } 123 | } 124 | 125 | //转换回不可变数组,并返回 126 | return [superArray copy]; 127 | 128 | } 129 | 130 | //return YES;表示一旦滑动就实时调用上面这个layoutAttributesForElementsInRect:方法 131 | - (BOOL) shouldInvalidateLayoutForBoundsChange:(CGRect)newBound { 132 | return YES; 133 | } 134 | 135 | 136 | @end 137 | -------------------------------------------------------------------------------- /XLPlainFlowLayoutDemo/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HebeTienCoder/XLPlainFlowLayout/ee440ffb0b31e996f9b2e3dd472ceba5e65d6733/XLPlainFlowLayoutDemo/.DS_Store -------------------------------------------------------------------------------- /XLPlainFlowLayoutDemo/XLPlainFlowLayout/XLPlainFlowLayout.h: -------------------------------------------------------------------------------- 1 | // 2 | // XLPlainFlowLayout.h 3 | // XLPlainFlowLayout 4 | // 5 | // Created by hebe on 15/7/30. 6 | // Copyright (c) 2015年 ___ZhangXiaoLiang___. All rights reserved. 7 | // 8 | // 工作邮箱E-mail: k52471@126.com 9 | 10 | #import 11 | 12 | @interface XLPlainFlowLayout : UICollectionViewFlowLayout 13 | 14 | @property (nonatomic, assign) CGFloat naviHeight;//默认为64.0, default is 64.0 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /XLPlainFlowLayoutDemo/XLPlainFlowLayout/XLPlainFlowLayout.m: -------------------------------------------------------------------------------- 1 | // 2 | // XLPlainFlowLayout.m 3 | // XLPlainFlowLayout 4 | // 5 | // Created by hebe on 15/7/30. 6 | // Copyright (c) 2015年 ___ZhangXiaoLiang___. All rights reserved. 7 | // 8 | // 工作邮箱E-mail: k52471@126.com 9 | 10 | #import "XLPlainFlowLayout.h" 11 | 12 | @implementation XLPlainFlowLayout 13 | 14 | -(instancetype)init 15 | { 16 | self = [super init]; 17 | if (self) 18 | { 19 | _naviHeight = 64.0; 20 | } 21 | return self; 22 | } 23 | 24 | 25 | - (NSArray *) layoutAttributesForElementsInRect:(CGRect)rect 26 | { 27 | //UICollectionViewLayoutAttributes:我称它为collectionView中的item(包括cell和header、footer这些)的《结构信息》 28 | //截取到父类所返回的数组(里面放的是当前屏幕所能展示的item的结构信息),并转化成不可变数组 29 | NSMutableArray *superArray = [[super layoutAttributesForElementsInRect:rect] mutableCopy]; 30 | 31 | //创建存索引的数组,无符号(正整数),无序(不能通过下标取值),不可重复(重复的话会自动过滤) 32 | NSMutableIndexSet *noneHeaderSections = [NSMutableIndexSet indexSet]; 33 | //遍历superArray,得到一个当前屏幕中所有的section数组 34 | for (UICollectionViewLayoutAttributes *attributes in superArray) 35 | { 36 | //如果当前的元素分类是一个cell,将cell所在的分区section加入数组,重复的话会自动过滤 37 | if (attributes.representedElementCategory == UICollectionElementCategoryCell) 38 | { 39 | [noneHeaderSections addIndex:attributes.indexPath.section]; 40 | } 41 | } 42 | 43 | //遍历superArray,将当前屏幕中拥有的header的section从数组中移除,得到一个当前屏幕中没有header的section数组 44 | //正常情况下,随着手指往上移,header脱离屏幕会被系统回收而cell尚在,也会触发该方法 45 | for (UICollectionViewLayoutAttributes *attributes in superArray) 46 | { 47 | //如果当前的元素是一个header,将header所在的section从数组中移除 48 | if ([attributes.representedElementKind isEqualToString:UICollectionElementKindSectionHeader]) 49 | { 50 | [noneHeaderSections removeIndex:attributes.indexPath.section]; 51 | } 52 | } 53 | 54 | //遍历当前屏幕中没有header的section数组 55 | [noneHeaderSections enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop){ 56 | 57 | //取到当前section中第一个item的indexPath 58 | NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:idx]; 59 | //获取当前section在正常情况下已经离开屏幕的header结构信息 60 | UICollectionViewLayoutAttributes *attributes = [self layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionHeader atIndexPath:indexPath]; 61 | 62 | //如果当前分区确实有因为离开屏幕而被系统回收的header 63 | if (attributes) 64 | { 65 | //将该header结构信息重新加入到superArray中去 66 | [superArray addObject:attributes]; 67 | } 68 | }]; 69 | 70 | //遍历superArray,改变header结构信息中的参数,使它可以在当前section还没完全离开屏幕的时候一直显示 71 | for (UICollectionViewLayoutAttributes *attributes in superArray) { 72 | 73 | //如果当前item是header 74 | if ([attributes.representedElementKind isEqualToString:UICollectionElementKindSectionHeader]) 75 | { 76 | //得到当前header所在分区的cell的数量 77 | NSInteger numberOfItemsInSection = [self.collectionView numberOfItemsInSection:attributes.indexPath.section]; 78 | //得到第一个item的indexPath 79 | NSIndexPath *firstItemIndexPath = [NSIndexPath indexPathForItem:0 inSection:attributes.indexPath.section]; 80 | //得到最后一个item的indexPath 81 | NSIndexPath *lastItemIndexPath = [NSIndexPath indexPathForItem:MAX(0, numberOfItemsInSection-1) inSection:attributes.indexPath.section]; 82 | //得到第一个item和最后一个item的结构信息 83 | UICollectionViewLayoutAttributes *firstItemAttributes, *lastItemAttributes; 84 | if (numberOfItemsInSection>0) 85 | { 86 | //cell有值,则获取第一个cell和最后一个cell的结构信息 87 | firstItemAttributes = [self layoutAttributesForItemAtIndexPath:firstItemIndexPath]; 88 | lastItemAttributes = [self layoutAttributesForItemAtIndexPath:lastItemIndexPath]; 89 | }else 90 | { 91 | //cell没值,就新建一个UICollectionViewLayoutAttributes 92 | firstItemAttributes = [UICollectionViewLayoutAttributes new]; 93 | //然后模拟出在当前分区中的唯一一个cell,cell在header的下面,高度为0,还与header隔着可能存在的sectionInset的top 94 | CGFloat y = CGRectGetMaxY(attributes.frame)+self.sectionInset.top; 95 | firstItemAttributes.frame = CGRectMake(0, y, 0, 0); 96 | //因为只有一个cell,所以最后一个cell等于第一个cell 97 | lastItemAttributes = firstItemAttributes; 98 | } 99 | 100 | //获取当前header的frame 101 | CGRect rect = attributes.frame; 102 | 103 | //当前的滑动距离 + 因为导航栏产生的偏移量,默认为64(如果app需求不同,需自己设置) 104 | CGFloat offset = self.collectionView.contentOffset.y + _naviHeight; 105 | //第一个cell的y值 - 当前header的高度 - 可能存在的sectionInset的top 106 | CGFloat headerY = firstItemAttributes.frame.origin.y - rect.size.height - self.sectionInset.top; 107 | 108 | //哪个大取哪个,保证header悬停 109 | //针对当前header基本上都是offset更加大,针对下一个header则会是headerY大,各自处理 110 | CGFloat maxY = MAX(offset,headerY); 111 | 112 | //最后一个cell的y值 + 最后一个cell的高度 + 可能存在的sectionInset的bottom - 当前header的高度 113 | //当当前section的footer或者下一个section的header接触到当前header的底部,计算出的headerMissingY即为有效值 114 | CGFloat headerMissingY = CGRectGetMaxY(lastItemAttributes.frame) + self.sectionInset.bottom - rect.size.height; 115 | 116 | //给rect的y赋新值,因为在最后消失的临界点要跟谁消失,所以取小 117 | rect.origin.y = MIN(maxY,headerMissingY); 118 | //给header的结构信息的frame重新赋值 119 | attributes.frame = rect; 120 | 121 | //如果按照正常情况下,header离开屏幕被系统回收,而header的层次关系又与cell相等,如果不去理会,会出现cell在header上面的情况 122 | //通过打印可以知道cell的层次关系zIndex数值为0,我们可以将header的zIndex设置成1,如果不放心,也可以将它设置成非常大,这里随便填了个7 123 | attributes.zIndex = 7; 124 | } 125 | } 126 | 127 | //转换回不可变数组,并返回 128 | return [superArray copy]; 129 | 130 | } 131 | 132 | //return YES;表示一旦滑动就实时调用上面这个layoutAttributesForElementsInRect:方法 133 | - (BOOL) shouldInvalidateLayoutForBoundsChange:(CGRect)newBound 134 | { 135 | return YES; 136 | } 137 | 138 | 139 | @end 140 | -------------------------------------------------------------------------------- /XLPlainFlowLayoutDemo/XLPlainFlowLayoutDemo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 817B314B1B69E155005B5AA3 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 817B314A1B69E155005B5AA3 /* main.m */; }; 11 | 817B314E1B69E155005B5AA3 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 817B314D1B69E155005B5AA3 /* AppDelegate.m */; }; 12 | 817B31511B69E155005B5AA3 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 817B31501B69E155005B5AA3 /* ViewController.m */; }; 13 | 817B31561B69E155005B5AA3 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 817B31551B69E155005B5AA3 /* Images.xcassets */; }; 14 | 817B31651B69E155005B5AA3 /* XLPlainFlowLayoutDemoTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 817B31641B69E155005B5AA3 /* XLPlainFlowLayoutDemoTests.m */; }; 15 | 817B31711B69E160005B5AA3 /* XLPlainFlowLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = 817B31701B69E160005B5AA3 /* XLPlainFlowLayout.m */; }; 16 | 817B31741B69E1F4005B5AA3 /* ReusableView.m in Sources */ = {isa = PBXBuildFile; fileRef = 817B31731B69E1F4005B5AA3 /* ReusableView.m */; }; 17 | /* End PBXBuildFile section */ 18 | 19 | /* Begin PBXContainerItemProxy section */ 20 | 817B315F1B69E155005B5AA3 /* PBXContainerItemProxy */ = { 21 | isa = PBXContainerItemProxy; 22 | containerPortal = 817B313D1B69E155005B5AA3 /* Project object */; 23 | proxyType = 1; 24 | remoteGlobalIDString = 817B31441B69E155005B5AA3; 25 | remoteInfo = XLPlainFlowLayoutDemo; 26 | }; 27 | /* End PBXContainerItemProxy section */ 28 | 29 | /* Begin PBXFileReference section */ 30 | 817B31451B69E155005B5AA3 /* XLPlainFlowLayoutDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = XLPlainFlowLayoutDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 31 | 817B31491B69E155005B5AA3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 32 | 817B314A1B69E155005B5AA3 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 33 | 817B314C1B69E155005B5AA3 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 34 | 817B314D1B69E155005B5AA3 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 35 | 817B314F1B69E155005B5AA3 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 36 | 817B31501B69E155005B5AA3 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 37 | 817B31551B69E155005B5AA3 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 38 | 817B315E1B69E155005B5AA3 /* XLPlainFlowLayoutDemoTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = XLPlainFlowLayoutDemoTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 39 | 817B31631B69E155005B5AA3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 40 | 817B31641B69E155005B5AA3 /* XLPlainFlowLayoutDemoTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = XLPlainFlowLayoutDemoTests.m; sourceTree = ""; }; 41 | 817B316F1B69E160005B5AA3 /* XLPlainFlowLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XLPlainFlowLayout.h; sourceTree = ""; }; 42 | 817B31701B69E160005B5AA3 /* XLPlainFlowLayout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = XLPlainFlowLayout.m; sourceTree = ""; }; 43 | 817B31721B69E1F4005B5AA3 /* ReusableView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ReusableView.h; sourceTree = ""; }; 44 | 817B31731B69E1F4005B5AA3 /* ReusableView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ReusableView.m; sourceTree = ""; }; 45 | /* End PBXFileReference section */ 46 | 47 | /* Begin PBXFrameworksBuildPhase section */ 48 | 817B31421B69E155005B5AA3 /* Frameworks */ = { 49 | isa = PBXFrameworksBuildPhase; 50 | buildActionMask = 2147483647; 51 | files = ( 52 | ); 53 | runOnlyForDeploymentPostprocessing = 0; 54 | }; 55 | 817B315B1B69E155005B5AA3 /* Frameworks */ = { 56 | isa = PBXFrameworksBuildPhase; 57 | buildActionMask = 2147483647; 58 | files = ( 59 | ); 60 | runOnlyForDeploymentPostprocessing = 0; 61 | }; 62 | /* End PBXFrameworksBuildPhase section */ 63 | 64 | /* Begin PBXGroup section */ 65 | 817B313C1B69E155005B5AA3 = { 66 | isa = PBXGroup; 67 | children = ( 68 | 817B316E1B69E160005B5AA3 /* XLPlainFlowLayout */, 69 | 817B31471B69E155005B5AA3 /* XLPlainFlowLayoutDemo */, 70 | 817B31611B69E155005B5AA3 /* XLPlainFlowLayoutDemoTests */, 71 | 817B31461B69E155005B5AA3 /* Products */, 72 | ); 73 | sourceTree = ""; 74 | }; 75 | 817B31461B69E155005B5AA3 /* Products */ = { 76 | isa = PBXGroup; 77 | children = ( 78 | 817B31451B69E155005B5AA3 /* XLPlainFlowLayoutDemo.app */, 79 | 817B315E1B69E155005B5AA3 /* XLPlainFlowLayoutDemoTests.xctest */, 80 | ); 81 | name = Products; 82 | sourceTree = ""; 83 | }; 84 | 817B31471B69E155005B5AA3 /* XLPlainFlowLayoutDemo */ = { 85 | isa = PBXGroup; 86 | children = ( 87 | 817B314C1B69E155005B5AA3 /* AppDelegate.h */, 88 | 817B314D1B69E155005B5AA3 /* AppDelegate.m */, 89 | 817B314F1B69E155005B5AA3 /* ViewController.h */, 90 | 817B31501B69E155005B5AA3 /* ViewController.m */, 91 | 817B31721B69E1F4005B5AA3 /* ReusableView.h */, 92 | 817B31731B69E1F4005B5AA3 /* ReusableView.m */, 93 | 817B31551B69E155005B5AA3 /* Images.xcassets */, 94 | 817B31481B69E155005B5AA3 /* Supporting Files */, 95 | ); 96 | path = XLPlainFlowLayoutDemo; 97 | sourceTree = ""; 98 | }; 99 | 817B31481B69E155005B5AA3 /* Supporting Files */ = { 100 | isa = PBXGroup; 101 | children = ( 102 | 817B31491B69E155005B5AA3 /* Info.plist */, 103 | 817B314A1B69E155005B5AA3 /* main.m */, 104 | ); 105 | name = "Supporting Files"; 106 | sourceTree = ""; 107 | }; 108 | 817B31611B69E155005B5AA3 /* XLPlainFlowLayoutDemoTests */ = { 109 | isa = PBXGroup; 110 | children = ( 111 | 817B31641B69E155005B5AA3 /* XLPlainFlowLayoutDemoTests.m */, 112 | 817B31621B69E155005B5AA3 /* Supporting Files */, 113 | ); 114 | path = XLPlainFlowLayoutDemoTests; 115 | sourceTree = ""; 116 | }; 117 | 817B31621B69E155005B5AA3 /* Supporting Files */ = { 118 | isa = PBXGroup; 119 | children = ( 120 | 817B31631B69E155005B5AA3 /* Info.plist */, 121 | ); 122 | name = "Supporting Files"; 123 | sourceTree = ""; 124 | }; 125 | 817B316E1B69E160005B5AA3 /* XLPlainFlowLayout */ = { 126 | isa = PBXGroup; 127 | children = ( 128 | 817B316F1B69E160005B5AA3 /* XLPlainFlowLayout.h */, 129 | 817B31701B69E160005B5AA3 /* XLPlainFlowLayout.m */, 130 | ); 131 | path = XLPlainFlowLayout; 132 | sourceTree = ""; 133 | }; 134 | /* End PBXGroup section */ 135 | 136 | /* Begin PBXNativeTarget section */ 137 | 817B31441B69E155005B5AA3 /* XLPlainFlowLayoutDemo */ = { 138 | isa = PBXNativeTarget; 139 | buildConfigurationList = 817B31681B69E155005B5AA3 /* Build configuration list for PBXNativeTarget "XLPlainFlowLayoutDemo" */; 140 | buildPhases = ( 141 | 817B31411B69E155005B5AA3 /* Sources */, 142 | 817B31421B69E155005B5AA3 /* Frameworks */, 143 | 817B31431B69E155005B5AA3 /* Resources */, 144 | ); 145 | buildRules = ( 146 | ); 147 | dependencies = ( 148 | ); 149 | name = XLPlainFlowLayoutDemo; 150 | productName = XLPlainFlowLayoutDemo; 151 | productReference = 817B31451B69E155005B5AA3 /* XLPlainFlowLayoutDemo.app */; 152 | productType = "com.apple.product-type.application"; 153 | }; 154 | 817B315D1B69E155005B5AA3 /* XLPlainFlowLayoutDemoTests */ = { 155 | isa = PBXNativeTarget; 156 | buildConfigurationList = 817B316B1B69E155005B5AA3 /* Build configuration list for PBXNativeTarget "XLPlainFlowLayoutDemoTests" */; 157 | buildPhases = ( 158 | 817B315A1B69E155005B5AA3 /* Sources */, 159 | 817B315B1B69E155005B5AA3 /* Frameworks */, 160 | 817B315C1B69E155005B5AA3 /* Resources */, 161 | ); 162 | buildRules = ( 163 | ); 164 | dependencies = ( 165 | 817B31601B69E155005B5AA3 /* PBXTargetDependency */, 166 | ); 167 | name = XLPlainFlowLayoutDemoTests; 168 | productName = XLPlainFlowLayoutDemoTests; 169 | productReference = 817B315E1B69E155005B5AA3 /* XLPlainFlowLayoutDemoTests.xctest */; 170 | productType = "com.apple.product-type.bundle.unit-test"; 171 | }; 172 | /* End PBXNativeTarget section */ 173 | 174 | /* Begin PBXProject section */ 175 | 817B313D1B69E155005B5AA3 /* Project object */ = { 176 | isa = PBXProject; 177 | attributes = { 178 | LastUpgradeCheck = 0640; 179 | ORGANIZATIONNAME = "___ZhangXiaoLiang___"; 180 | TargetAttributes = { 181 | 817B31441B69E155005B5AA3 = { 182 | CreatedOnToolsVersion = 6.4; 183 | }; 184 | 817B315D1B69E155005B5AA3 = { 185 | CreatedOnToolsVersion = 6.4; 186 | TestTargetID = 817B31441B69E155005B5AA3; 187 | }; 188 | }; 189 | }; 190 | buildConfigurationList = 817B31401B69E155005B5AA3 /* Build configuration list for PBXProject "XLPlainFlowLayoutDemo" */; 191 | compatibilityVersion = "Xcode 3.2"; 192 | developmentRegion = English; 193 | hasScannedForEncodings = 0; 194 | knownRegions = ( 195 | en, 196 | Base, 197 | ); 198 | mainGroup = 817B313C1B69E155005B5AA3; 199 | productRefGroup = 817B31461B69E155005B5AA3 /* Products */; 200 | projectDirPath = ""; 201 | projectRoot = ""; 202 | targets = ( 203 | 817B31441B69E155005B5AA3 /* XLPlainFlowLayoutDemo */, 204 | 817B315D1B69E155005B5AA3 /* XLPlainFlowLayoutDemoTests */, 205 | ); 206 | }; 207 | /* End PBXProject section */ 208 | 209 | /* Begin PBXResourcesBuildPhase section */ 210 | 817B31431B69E155005B5AA3 /* Resources */ = { 211 | isa = PBXResourcesBuildPhase; 212 | buildActionMask = 2147483647; 213 | files = ( 214 | 817B31561B69E155005B5AA3 /* Images.xcassets in Resources */, 215 | ); 216 | runOnlyForDeploymentPostprocessing = 0; 217 | }; 218 | 817B315C1B69E155005B5AA3 /* Resources */ = { 219 | isa = PBXResourcesBuildPhase; 220 | buildActionMask = 2147483647; 221 | files = ( 222 | ); 223 | runOnlyForDeploymentPostprocessing = 0; 224 | }; 225 | /* End PBXResourcesBuildPhase section */ 226 | 227 | /* Begin PBXSourcesBuildPhase section */ 228 | 817B31411B69E155005B5AA3 /* Sources */ = { 229 | isa = PBXSourcesBuildPhase; 230 | buildActionMask = 2147483647; 231 | files = ( 232 | 817B31711B69E160005B5AA3 /* XLPlainFlowLayout.m in Sources */, 233 | 817B31511B69E155005B5AA3 /* ViewController.m in Sources */, 234 | 817B314E1B69E155005B5AA3 /* AppDelegate.m in Sources */, 235 | 817B314B1B69E155005B5AA3 /* main.m in Sources */, 236 | 817B31741B69E1F4005B5AA3 /* ReusableView.m in Sources */, 237 | ); 238 | runOnlyForDeploymentPostprocessing = 0; 239 | }; 240 | 817B315A1B69E155005B5AA3 /* Sources */ = { 241 | isa = PBXSourcesBuildPhase; 242 | buildActionMask = 2147483647; 243 | files = ( 244 | 817B31651B69E155005B5AA3 /* XLPlainFlowLayoutDemoTests.m in Sources */, 245 | ); 246 | runOnlyForDeploymentPostprocessing = 0; 247 | }; 248 | /* End PBXSourcesBuildPhase section */ 249 | 250 | /* Begin PBXTargetDependency section */ 251 | 817B31601B69E155005B5AA3 /* PBXTargetDependency */ = { 252 | isa = PBXTargetDependency; 253 | target = 817B31441B69E155005B5AA3 /* XLPlainFlowLayoutDemo */; 254 | targetProxy = 817B315F1B69E155005B5AA3 /* PBXContainerItemProxy */; 255 | }; 256 | /* End PBXTargetDependency section */ 257 | 258 | /* Begin XCBuildConfiguration section */ 259 | 817B31661B69E155005B5AA3 /* Debug */ = { 260 | isa = XCBuildConfiguration; 261 | buildSettings = { 262 | ALWAYS_SEARCH_USER_PATHS = NO; 263 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 264 | CLANG_CXX_LIBRARY = "libc++"; 265 | CLANG_ENABLE_MODULES = YES; 266 | CLANG_ENABLE_OBJC_ARC = YES; 267 | CLANG_WARN_BOOL_CONVERSION = YES; 268 | CLANG_WARN_CONSTANT_CONVERSION = YES; 269 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 270 | CLANG_WARN_EMPTY_BODY = YES; 271 | CLANG_WARN_ENUM_CONVERSION = YES; 272 | CLANG_WARN_INT_CONVERSION = YES; 273 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 274 | CLANG_WARN_UNREACHABLE_CODE = YES; 275 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 276 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 277 | COPY_PHASE_STRIP = NO; 278 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 279 | ENABLE_STRICT_OBJC_MSGSEND = YES; 280 | GCC_C_LANGUAGE_STANDARD = gnu99; 281 | GCC_DYNAMIC_NO_PIC = NO; 282 | GCC_NO_COMMON_BLOCKS = YES; 283 | GCC_OPTIMIZATION_LEVEL = 0; 284 | GCC_PREPROCESSOR_DEFINITIONS = ( 285 | "DEBUG=1", 286 | "$(inherited)", 287 | ); 288 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 289 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 290 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 291 | GCC_WARN_UNDECLARED_SELECTOR = YES; 292 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 293 | GCC_WARN_UNUSED_FUNCTION = YES; 294 | GCC_WARN_UNUSED_VARIABLE = YES; 295 | IPHONEOS_DEPLOYMENT_TARGET = 8.4; 296 | MTL_ENABLE_DEBUG_INFO = YES; 297 | ONLY_ACTIVE_ARCH = YES; 298 | SDKROOT = iphoneos; 299 | }; 300 | name = Debug; 301 | }; 302 | 817B31671B69E155005B5AA3 /* Release */ = { 303 | isa = XCBuildConfiguration; 304 | buildSettings = { 305 | ALWAYS_SEARCH_USER_PATHS = NO; 306 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 307 | CLANG_CXX_LIBRARY = "libc++"; 308 | CLANG_ENABLE_MODULES = YES; 309 | CLANG_ENABLE_OBJC_ARC = YES; 310 | CLANG_WARN_BOOL_CONVERSION = YES; 311 | CLANG_WARN_CONSTANT_CONVERSION = YES; 312 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 313 | CLANG_WARN_EMPTY_BODY = YES; 314 | CLANG_WARN_ENUM_CONVERSION = YES; 315 | CLANG_WARN_INT_CONVERSION = YES; 316 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 317 | CLANG_WARN_UNREACHABLE_CODE = YES; 318 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 319 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 320 | COPY_PHASE_STRIP = NO; 321 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 322 | ENABLE_NS_ASSERTIONS = NO; 323 | ENABLE_STRICT_OBJC_MSGSEND = YES; 324 | GCC_C_LANGUAGE_STANDARD = gnu99; 325 | GCC_NO_COMMON_BLOCKS = YES; 326 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 327 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 328 | GCC_WARN_UNDECLARED_SELECTOR = YES; 329 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 330 | GCC_WARN_UNUSED_FUNCTION = YES; 331 | GCC_WARN_UNUSED_VARIABLE = YES; 332 | IPHONEOS_DEPLOYMENT_TARGET = 8.4; 333 | MTL_ENABLE_DEBUG_INFO = NO; 334 | SDKROOT = iphoneos; 335 | VALIDATE_PRODUCT = YES; 336 | }; 337 | name = Release; 338 | }; 339 | 817B31691B69E155005B5AA3 /* Debug */ = { 340 | isa = XCBuildConfiguration; 341 | buildSettings = { 342 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 343 | INFOPLIST_FILE = XLPlainFlowLayoutDemo/Info.plist; 344 | IPHONEOS_DEPLOYMENT_TARGET = 7.0; 345 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 346 | PRODUCT_NAME = "$(TARGET_NAME)"; 347 | }; 348 | name = Debug; 349 | }; 350 | 817B316A1B69E155005B5AA3 /* Release */ = { 351 | isa = XCBuildConfiguration; 352 | buildSettings = { 353 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 354 | INFOPLIST_FILE = XLPlainFlowLayoutDemo/Info.plist; 355 | IPHONEOS_DEPLOYMENT_TARGET = 7.0; 356 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 357 | PRODUCT_NAME = "$(TARGET_NAME)"; 358 | }; 359 | name = Release; 360 | }; 361 | 817B316C1B69E155005B5AA3 /* Debug */ = { 362 | isa = XCBuildConfiguration; 363 | buildSettings = { 364 | BUNDLE_LOADER = "$(TEST_HOST)"; 365 | FRAMEWORK_SEARCH_PATHS = ( 366 | "$(SDKROOT)/Developer/Library/Frameworks", 367 | "$(inherited)", 368 | ); 369 | GCC_PREPROCESSOR_DEFINITIONS = ( 370 | "DEBUG=1", 371 | "$(inherited)", 372 | ); 373 | INFOPLIST_FILE = XLPlainFlowLayoutDemoTests/Info.plist; 374 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 375 | PRODUCT_NAME = "$(TARGET_NAME)"; 376 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/XLPlainFlowLayoutDemo.app/XLPlainFlowLayoutDemo"; 377 | }; 378 | name = Debug; 379 | }; 380 | 817B316D1B69E155005B5AA3 /* Release */ = { 381 | isa = XCBuildConfiguration; 382 | buildSettings = { 383 | BUNDLE_LOADER = "$(TEST_HOST)"; 384 | FRAMEWORK_SEARCH_PATHS = ( 385 | "$(SDKROOT)/Developer/Library/Frameworks", 386 | "$(inherited)", 387 | ); 388 | INFOPLIST_FILE = XLPlainFlowLayoutDemoTests/Info.plist; 389 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 390 | PRODUCT_NAME = "$(TARGET_NAME)"; 391 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/XLPlainFlowLayoutDemo.app/XLPlainFlowLayoutDemo"; 392 | }; 393 | name = Release; 394 | }; 395 | /* End XCBuildConfiguration section */ 396 | 397 | /* Begin XCConfigurationList section */ 398 | 817B31401B69E155005B5AA3 /* Build configuration list for PBXProject "XLPlainFlowLayoutDemo" */ = { 399 | isa = XCConfigurationList; 400 | buildConfigurations = ( 401 | 817B31661B69E155005B5AA3 /* Debug */, 402 | 817B31671B69E155005B5AA3 /* Release */, 403 | ); 404 | defaultConfigurationIsVisible = 0; 405 | defaultConfigurationName = Release; 406 | }; 407 | 817B31681B69E155005B5AA3 /* Build configuration list for PBXNativeTarget "XLPlainFlowLayoutDemo" */ = { 408 | isa = XCConfigurationList; 409 | buildConfigurations = ( 410 | 817B31691B69E155005B5AA3 /* Debug */, 411 | 817B316A1B69E155005B5AA3 /* Release */, 412 | ); 413 | defaultConfigurationIsVisible = 0; 414 | defaultConfigurationName = Release; 415 | }; 416 | 817B316B1B69E155005B5AA3 /* Build configuration list for PBXNativeTarget "XLPlainFlowLayoutDemoTests" */ = { 417 | isa = XCConfigurationList; 418 | buildConfigurations = ( 419 | 817B316C1B69E155005B5AA3 /* Debug */, 420 | 817B316D1B69E155005B5AA3 /* Release */, 421 | ); 422 | defaultConfigurationIsVisible = 0; 423 | defaultConfigurationName = Release; 424 | }; 425 | /* End XCConfigurationList section */ 426 | }; 427 | rootObject = 817B313D1B69E155005B5AA3 /* Project object */; 428 | } 429 | -------------------------------------------------------------------------------- /XLPlainFlowLayoutDemo/XLPlainFlowLayoutDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /XLPlainFlowLayoutDemo/XLPlainFlowLayoutDemo.xcodeproj/project.xcworkspace/xcshareddata/XLPlainFlowLayoutDemo.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectFavoriteDictionaryKey 6 | 7 | IDESourceControlProjectIdentifier 8 | D2580A17-47ED-4230-B52B-B84A4B3CCBC0 9 | IDESourceControlProjectName 10 | XLPlainFlowLayoutDemo 11 | IDESourceControlProjectOriginsDictionary 12 | 13 | C1B4B90BEC9D0C44A27E08D164ECF16339AE2035 14 | https://github.com/HebeTienCoder/XLPlainFlowLayout.git 15 | 16 | IDESourceControlProjectPath 17 | XLPlainFlowLayoutDemo/XLPlainFlowLayoutDemo.xcodeproj 18 | IDESourceControlProjectRelativeInstallPathDictionary 19 | 20 | C1B4B90BEC9D0C44A27E08D164ECF16339AE2035 21 | ../../.. 22 | 23 | IDESourceControlProjectURL 24 | https://github.com/HebeTienCoder/XLPlainFlowLayout.git 25 | IDESourceControlProjectVersion 26 | 111 27 | IDESourceControlProjectWCCIdentifier 28 | C1B4B90BEC9D0C44A27E08D164ECF16339AE2035 29 | IDESourceControlProjectWCConfigurations 30 | 31 | 32 | IDESourceControlRepositoryExtensionIdentifierKey 33 | public.vcs.git 34 | IDESourceControlWCCIdentifierKey 35 | C1B4B90BEC9D0C44A27E08D164ECF16339AE2035 36 | IDESourceControlWCCName 37 | XLPlainFlowLayout 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /XLPlainFlowLayoutDemo/XLPlainFlowLayoutDemo.xcodeproj/project.xcworkspace/xcuserdata/hebe.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HebeTienCoder/XLPlainFlowLayout/ee440ffb0b31e996f9b2e3dd472ceba5e65d6733/XLPlainFlowLayoutDemo/XLPlainFlowLayoutDemo.xcodeproj/project.xcworkspace/xcuserdata/hebe.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /XLPlainFlowLayoutDemo/XLPlainFlowLayoutDemo.xcodeproj/xcuserdata/hebe.xcuserdatad/xcschemes/XLPlainFlowLayoutDemo.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 38 | 39 | 44 | 45 | 47 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 65 | 66 | 75 | 77 | 83 | 84 | 85 | 86 | 87 | 88 | 94 | 96 | 102 | 103 | 104 | 105 | 107 | 108 | 111 | 112 | 113 | -------------------------------------------------------------------------------- /XLPlainFlowLayoutDemo/XLPlainFlowLayoutDemo.xcodeproj/xcuserdata/hebe.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | XLPlainFlowLayoutDemo.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 817B31441B69E155005B5AA3 16 | 17 | primary 18 | 19 | 20 | 817B315D1B69E155005B5AA3 21 | 22 | primary 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /XLPlainFlowLayoutDemo/XLPlainFlowLayoutDemo/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // XLPlainFlowLayoutDemo 4 | // 5 | // Created by hebe on 15/7/30. 6 | // Copyright (c) 2015年 ___ZhangXiaoLiang___. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /XLPlainFlowLayoutDemo/XLPlainFlowLayoutDemo/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // XLPlainFlowLayoutDemo 4 | // 5 | // Created by hebe on 15/7/30. 6 | // Copyright (c) 2015年 ___ZhangXiaoLiang___. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | #import "ViewController.h" 11 | 12 | @interface AppDelegate () 13 | 14 | @end 15 | 16 | @implementation AppDelegate 17 | 18 | 19 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 20 | // Override point for customization after application launch. 21 | 22 | self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; 23 | self.window.backgroundColor = [UIColor whiteColor]; 24 | // self.window.rootViewController = [ViewController new]; 25 | self.window.rootViewController = [[UINavigationController alloc] initWithRootViewController:[ViewController new]]; 26 | [self.window makeKeyAndVisible]; 27 | return YES; 28 | } 29 | 30 | - (void)applicationWillResignActive:(UIApplication *)application { 31 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 32 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 33 | } 34 | 35 | - (void)applicationDidEnterBackground:(UIApplication *)application { 36 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 37 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 38 | } 39 | 40 | - (void)applicationWillEnterForeground:(UIApplication *)application { 41 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 42 | } 43 | 44 | - (void)applicationDidBecomeActive:(UIApplication *)application { 45 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 46 | } 47 | 48 | - (void)applicationWillTerminate:(UIApplication *)application { 49 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 50 | } 51 | 52 | @end 53 | -------------------------------------------------------------------------------- /XLPlainFlowLayoutDemo/XLPlainFlowLayoutDemo/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | } 33 | ], 34 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } -------------------------------------------------------------------------------- /XLPlainFlowLayoutDemo/XLPlainFlowLayoutDemo/Images.xcassets/LaunchImage.launchimage/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "orientation" : "portrait", 5 | "idiom" : "iphone", 6 | "minimum-system-version" : "7.0", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "orientation" : "portrait", 11 | "idiom" : "iphone", 12 | "minimum-system-version" : "7.0", 13 | "subtype" : "retina4", 14 | "scale" : "2x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /XLPlainFlowLayoutDemo/XLPlainFlowLayoutDemo/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | wahaha.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /XLPlainFlowLayoutDemo/XLPlainFlowLayoutDemo/ReusableView.h: -------------------------------------------------------------------------------- 1 | // 2 | // ReusableView.h 3 | // PlainLayout 4 | // 5 | // Created by hebe on 15/7/30. 6 | // Copyright (c) 2015年 ___ZhangXiaoLiang___. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ReusableView : UICollectionReusableView 12 | 13 | @property (nonatomic, strong) NSString *text; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /XLPlainFlowLayoutDemo/XLPlainFlowLayoutDemo/ReusableView.m: -------------------------------------------------------------------------------- 1 | // 2 | // ReusableView.m 3 | // PlainLayout 4 | // 5 | // Created by hebe on 15/7/30. 6 | // Copyright (c) 2015年 ___ZhangXiaoLiang___. All rights reserved. 7 | // 8 | 9 | #import "ReusableView.h" 10 | 11 | @implementation ReusableView 12 | 13 | -(instancetype)initWithFrame:(CGRect)frame 14 | { 15 | self = [super initWithFrame:frame]; 16 | if (self) 17 | { 18 | UILabel *label = [[UILabel alloc]initWithFrame:self.bounds]; 19 | label.textAlignment = NSTextAlignmentCenter; 20 | [self addSubview:label]; 21 | } 22 | return self; 23 | } 24 | 25 | -(void)setText:(NSString *)text 26 | { 27 | _text = text; 28 | 29 | ((UILabel *)self.subviews[0]).text = text; 30 | } 31 | 32 | @end 33 | -------------------------------------------------------------------------------- /XLPlainFlowLayoutDemo/XLPlainFlowLayoutDemo/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // XLPlainFlowLayoutDemo 4 | // 5 | // Created by hebe on 15/7/30. 6 | // Copyright (c) 2015年 ___ZhangXiaoLiang___. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | @interface ViewController : UICollectionViewController 13 | 14 | 15 | @end 16 | 17 | -------------------------------------------------------------------------------- /XLPlainFlowLayoutDemo/XLPlainFlowLayoutDemo/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // XLPlainFlowLayoutDemo 4 | // 5 | // Created by hebe on 15/7/30. 6 | // Copyright (c) 2015年 ___ZhangXiaoLiang___. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | #import "ReusableView.h" 11 | #import "XLPlainFlowLayout.h" 12 | 13 | @interface ViewController () 14 | 15 | @end 16 | 17 | @implementation ViewController 18 | static NSString *cellID = @"cellID"; 19 | static NSString *headerID = @"headerID"; 20 | static NSString *footerID = @"footerID"; 21 | 22 | -(instancetype)init 23 | { 24 | XLPlainFlowLayout *layout = [XLPlainFlowLayout new]; 25 | layout.itemSize = CGSizeMake(100, 100); 26 | layout.sectionInset = UIEdgeInsetsMake(10, 10, 10, 10); 27 | layout.naviHeight = 44.0; 28 | return [self initWithCollectionViewLayout:layout]; 29 | } 30 | 31 | - (void)viewDidLoad { 32 | [super viewDidLoad]; 33 | 34 | self.navigationItem.title = @"XLPlainFlowLayoutDemo"; 35 | 36 | self.collectionView.backgroundColor = [UIColor whiteColor]; 37 | [self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:cellID]; 38 | [self.collectionView registerClass:[ReusableView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:headerID]; 39 | [self.collectionView registerClass:[ReusableView class] forSupplementaryViewOfKind:UICollectionElementKindSectionFooter withReuseIdentifier:footerID]; 40 | } 41 | 42 | - (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView 43 | { 44 | return 10; 45 | } 46 | 47 | - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section 48 | { 49 | if (section==2) { 50 | return 0; 51 | } 52 | return 10; 53 | } 54 | 55 | -(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath 56 | { 57 | UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellID forIndexPath:indexPath]; 58 | cell.backgroundColor = indexPath.section%2?[UIColor redColor]:[UIColor cyanColor]; 59 | return cell; 60 | } 61 | 62 | - (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath { 63 | 64 | if (kind==UICollectionElementKindSectionFooter) { 65 | ReusableView *footer = [collectionView dequeueReusableSupplementaryViewOfKind:kind withReuseIdentifier:footerID forIndexPath:indexPath]; 66 | footer.backgroundColor = [UIColor yellowColor]; 67 | footer.text = [NSString stringWithFormat:@"第%ld个分区的footer",indexPath.section]; 68 | return footer; 69 | } 70 | 71 | if (indexPath.section >0) { 72 | ReusableView *header = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:headerID forIndexPath:indexPath]; 73 | header.backgroundColor = indexPath.section%2?[[UIColor blackColor] colorWithAlphaComponent:0.5] : [[UIColor blueColor] colorWithAlphaComponent:0.5]; 74 | header.text = [NSString stringWithFormat:@"第%ld个分区的header",indexPath.section]; 75 | return header; 76 | } 77 | return nil; 78 | } 79 | 80 | - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section 81 | { 82 | if (section>0) { 83 | return CGSizeMake(0, 44); 84 | } 85 | return CGSizeZero; 86 | } 87 | 88 | - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForFooterInSection:(NSInteger)section 89 | { 90 | if (section==3) { 91 | return CGSizeZero; 92 | } 93 | return CGSizeMake(0, 20); 94 | } 95 | 96 | -(BOOL)prefersStatusBarHidden 97 | { 98 | return YES; 99 | } 100 | 101 | 102 | @end 103 | -------------------------------------------------------------------------------- /XLPlainFlowLayoutDemo/XLPlainFlowLayoutDemo/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // XLPlainFlowLayoutDemo 4 | // 5 | // Created by hebe on 15/7/30. 6 | // Copyright (c) 2015年 ___ZhangXiaoLiang___. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /XLPlainFlowLayoutDemo/XLPlainFlowLayoutDemoTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | wahaha.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /XLPlainFlowLayoutDemo/XLPlainFlowLayoutDemoTests/XLPlainFlowLayoutDemoTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // XLPlainFlowLayoutDemoTests.m 3 | // XLPlainFlowLayoutDemoTests 4 | // 5 | // Created by hebe on 15/7/30. 6 | // Copyright (c) 2015年 ___ZhangXiaoLiang___. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @interface XLPlainFlowLayoutDemoTests : XCTestCase 13 | 14 | @end 15 | 16 | @implementation XLPlainFlowLayoutDemoTests 17 | 18 | - (void)setUp { 19 | [super setUp]; 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | } 22 | 23 | - (void)tearDown { 24 | // Put teardown code here. This method is called after the invocation of each test method in the class. 25 | [super tearDown]; 26 | } 27 | 28 | - (void)testExample { 29 | // This is an example of a functional test case. 30 | XCTAssert(YES, @"Pass"); 31 | } 32 | 33 | - (void)testPerformanceExample { 34 | // This is an example of a performance test case. 35 | [self measureBlock:^{ 36 | // Put the code you want to measure the time of here. 37 | }]; 38 | } 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HebeTienCoder/XLPlainFlowLayout/ee440ffb0b31e996f9b2e3dd472ceba5e65d6733/demo.gif --------------------------------------------------------------------------------