├── .gitignore ├── ASJCollectionViewFillLayout.podspec ├── ASJCollectionViewFillLayout ├── ASJCollectionViewFillLayout.h └── ASJCollectionViewFillLayout.m ├── CHANGELOG.md ├── Example ├── ASJCollectionViewFillLayoutExample.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ └── contents.xcworkspacedata └── ASJCollectionViewFillLayoutExample │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ ├── Brand Assets.launchimage │ │ ├── Contents.json │ │ ├── splash-1242-2208.png │ │ ├── splash-640-1136.png │ │ ├── splash-640-960.png │ │ └── splash-750-1334.png │ └── Contents.json │ ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard │ ├── Info.plist │ ├── ViewController.h │ ├── ViewController.m │ └── main.m ├── Images ├── 7.png └── 8.png ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | .DS_Store 4 | build/ 5 | *.pbxuser 6 | !default.pbxuser 7 | *.mode1v3 8 | !default.mode1v3 9 | *.mode2v3 10 | !default.mode2v3 11 | *.perspectivev3 12 | !default.perspectivev3 13 | xcuserdata 14 | *.xccheckout 15 | *.moved-aside 16 | DerivedData 17 | *.hmap 18 | *.ipa 19 | *.xcuserstate 20 | # CocoaPods 21 | # 22 | # We recommend against adding the Pods directory to your .gitignore. However 23 | # you should judge for yourself, the pros and cons are mentioned at: 24 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control 25 | # 26 | Pods/ -------------------------------------------------------------------------------- /ASJCollectionViewFillLayout.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = 'ASJCollectionViewFillLayout' 3 | s.version = '2.1' 4 | s.platform = :ios, '9.0' 5 | s.license = { :type => 'MIT' } 6 | s.homepage = 'https://github.com/sdpjswl/ASJCollectionViewFillLayout' 7 | s.authors = { 'Sudeep' => 'sdpjswl1@gmail.com' } 8 | s.summary = 'A flow layout style UICollectionViewLayout that fills the full width of the collection view' 9 | s.source = { :git => 'https://github.com/sdpjswl/ASJCollectionViewFillLayout.git', :tag => s.version } 10 | s.source_files = 'ASJCollectionViewFillLayout/*.{h,m}' 11 | s.requires_arc = true 12 | end 13 | -------------------------------------------------------------------------------- /ASJCollectionViewFillLayout/ASJCollectionViewFillLayout.h: -------------------------------------------------------------------------------- 1 | // 2 | // ASJCollectionViewFillLayout.h 3 | // 4 | // Copyright (c) 2015 Sudeep Jaiswal 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | @import UIKit; 25 | 26 | NS_ASSUME_NONNULL_BEGIN 27 | 28 | typedef NS_ENUM(NSInteger, ASJCollectionViewFillLayoutDirection) 29 | { 30 | ASJCollectionViewFillLayoutVertical, 31 | ASJCollectionViewFillLayoutHorizontal 32 | }; 33 | 34 | @protocol ASJCollectionViewFillLayoutDelegate 35 | 36 | @optional 37 | 38 | /** 39 | * Sets the number of items in one row or column. For `ASJCollectionViewFillLayoutVertical`, the collection view will scroll vertically so this property refers to the item count in one row. 40 | * Similarly, for `ASJCollectionViewFillLayoutHorizontal`, the collection view scrolls horizontally and this property refers to the item count in one column. 41 | * In each case, the width or height for each item will be calculated accordingly. 42 | */ 43 | - (NSInteger)numberOfItemsInSide; 44 | 45 | /** 46 | * Sets the width or height for a collection view item, depending on the direction of the layout. 47 | * By default, the direction is `ASJCollectionViewFillLayoutVertical` for which the item width will be calculated and the item height may vary. 48 | * For `ASJCollectionViewFillLayoutVertical`, the item height will be calculated and the item width may vary. 49 | * If `itemLength` is not set, it defaults to the calculated item width or height. 50 | */ 51 | - (CGFloat)itemLength; 52 | 53 | /** 54 | * Sets the 'inter-item spacing' between two collection 55 | * view items. This will also set the padding between an 56 | * item and the collection view boundary. 57 | */ 58 | - (CGFloat)itemSpacing; 59 | 60 | @end 61 | 62 | @interface ASJCollectionViewFillLayout : UICollectionViewLayout 63 | 64 | /** 65 | * Sets the number of items in one row or column. For `ASJCollectionViewFillLayoutVertical`, the collection view will scroll vertically so this property refers to the item count in one row. 66 | * Similarly, for `ASJCollectionViewFillLayoutHorizontal`, the collection view scrolls horizontally and this property refers to the item count in one column. 67 | * In each case, the width or height for each item will be calculated accordingly. 68 | */ 69 | @property (assign, nonatomic) NSInteger numberOfItemsInSide; 70 | 71 | /** 72 | * Sets the width or height for a collection view item, depending on the direction of the layout. 73 | * By default, the direction is `ASJCollectionViewFillLayoutVertical` for which the item width will be calculated and the item height may vary. 74 | * For `ASJCollectionViewFillLayoutVertical`, the item height will be calculated and the item width may vary. 75 | * If `itemLength` is not set, it defaults to the calculated item width or height. 76 | */ 77 | @property (assign, nonatomic) CGFloat itemLength; 78 | 79 | /** 80 | * Sets the 'inter-item spacing' between two collection 81 | * view items. This will also set the padding between an 82 | * item and the collection view boundary. 83 | */ 84 | @property (assign, nonatomic) CGFloat itemSpacing; 85 | 86 | /** 87 | * Arranges the collection view items vertically or horizontally. Defaults to `ASJCollectionViewFillLayoutVertical`. 88 | */ 89 | @property (assign, nonatomic) ASJCollectionViewFillLayoutDirection direction; 90 | 91 | /** 92 | * Sets the stretching behavior for the items in the last 'row' or 'column'. 93 | * If set to NO all items will have the same size, YES stretches them 94 | * across the collection view width or height (default behavior). 95 | */ 96 | @property (assign, nonatomic) BOOL stretchesLastItems; 97 | 98 | /** 99 | * The delegate for the fill layout. You must set this 100 | * in order to use the methods defined in the protocol. 101 | */ 102 | @property (nullable, weak, nonatomic) id delegate; 103 | 104 | @end 105 | 106 | NS_ASSUME_NONNULL_END 107 | -------------------------------------------------------------------------------- /ASJCollectionViewFillLayout/ASJCollectionViewFillLayout.m: -------------------------------------------------------------------------------- 1 | // 2 | // ASJCollectionViewFillLayout.m 3 | // 4 | // Copyright (c) 2015 Sudeep Jaiswal 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #import "ASJCollectionViewFillLayout.h" 25 | 26 | // Thanks: http://damir.me/implementing-uicollectionview-layout 27 | 28 | @interface ASJCollectionViewFillLayout () 29 | 30 | @property (readonly, nonatomic) NSInteger numberOfItemsInCollectionView; 31 | @property (assign, nonatomic) CGSize contentSize; 32 | @property (copy, nonatomic) NSIndexSet *extraIndexes; 33 | @property (copy, nonatomic) NSArray *itemAttributes; 34 | @property (readonly, weak, nonatomic) NSNotificationCenter *notificationCenter; 35 | 36 | - (void)setup; 37 | - (void)setupDefaults; 38 | - (void)prepareVerticalLayout; 39 | - (void)prepareHorizontalLayout; 40 | 41 | @end 42 | 43 | @implementation ASJCollectionViewFillLayout 44 | 45 | - (instancetype)init 46 | { 47 | self = [super init]; 48 | if (self) { 49 | [self setup]; 50 | } 51 | return self; 52 | } 53 | 54 | - (instancetype)initWithCoder:(NSCoder *)coder 55 | { 56 | self = [super initWithCoder:coder]; 57 | if (self) { 58 | [self setup]; 59 | } 60 | return self; 61 | } 62 | 63 | #pragma mark - Setup 64 | 65 | - (void)setup 66 | { 67 | [self setupDefaults]; 68 | [self listenForOrientationChanges]; 69 | } 70 | 71 | - (void)setupDefaults 72 | { 73 | self.numberOfItemsInSide = 1; 74 | self.itemSpacing = 8.0f; 75 | self.direction = ASJCollectionViewFillLayoutVertical; 76 | self.stretchesLastItems = YES; 77 | } 78 | 79 | #pragma mark - Orientation 80 | 81 | - (void)listenForOrientationChanges 82 | { 83 | [self.notificationCenter addObserver:self selector:@selector(orientationDidChange:) name:UIDeviceOrientationDidChangeNotification object:nil]; 84 | } 85 | 86 | - (void)orientationDidChange:(NSNotification *)note 87 | { 88 | [self invalidateLayout]; 89 | } 90 | 91 | - (void)dealloc 92 | { 93 | [self.notificationCenter removeObserver:self]; 94 | } 95 | 96 | - (NSNotificationCenter *)notificationCenter 97 | { 98 | return [NSNotificationCenter defaultCenter]; 99 | } 100 | 101 | #pragma mark - Overrides 102 | 103 | - (void)prepareLayout 104 | { 105 | [super prepareLayout]; 106 | 107 | // read values from delegate if available 108 | if ([_delegate respondsToSelector:@selector(numberOfItemsInSide)]) 109 | { 110 | _numberOfItemsInSide = [_delegate numberOfItemsInSide]; 111 | } 112 | if ([_delegate respondsToSelector:@selector(itemLength)]) 113 | NSAssert(_numberOfItemsInSide > 0, @"Collection view must have at least one item in row. Set 'numberOfItemsInSide'."); 114 | 115 | if ([_delegate respondsToSelector:@selector(itemLength)]) 116 | { 117 | _itemLength = [_delegate itemLength]; 118 | } 119 | if ([_delegate respondsToSelector:@selector(itemSpacing)]) 120 | { 121 | _itemSpacing = [_delegate itemSpacing]; 122 | } 123 | 124 | _itemAttributes = nil; 125 | _extraIndexes = nil; 126 | _contentSize = CGSizeZero; 127 | 128 | // store indexes of any extra items, if present 129 | NSInteger numberOfItems = self.numberOfItemsInCollectionView; 130 | NSInteger extraItems = numberOfItems % _numberOfItemsInSide; 131 | 132 | if (extraItems > 0) 133 | { 134 | NSMutableIndexSet *indexes = [[NSMutableIndexSet alloc] init]; 135 | for (int i=0; i rowHeight) { 186 | rowHeight = itemSize.height; 187 | } 188 | 189 | // create layout attributes objects 190 | NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0]; 191 | UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath]; 192 | attributes.frame = CGRectIntegral(CGRectMake(xOffset, yOffset, itemSize.width, itemSize.height)); 193 | [layoutAttributes addObject:attributes]; 194 | 195 | // move 'x' for next item 196 | xOffset = xOffset + itemSize.width + _itemSpacing; 197 | column++; 198 | 199 | // if item was the last one in current row 200 | // special case handled for when number of items is lesser than 201 | // number of items in row 202 | if ((numberOfItems < _numberOfItemsInSide && column == numberOfItems) || 203 | (column == _numberOfItemsInSide)) 204 | { 205 | if (xOffset > contentWidth) { 206 | contentWidth = xOffset; 207 | } 208 | 209 | // reset 210 | column = 0; 211 | xOffset = _itemSpacing; 212 | yOffset += rowHeight + _itemSpacing; 213 | } 214 | 215 | // calculate content height 216 | UICollectionViewLayoutAttributes *lastAttributes = layoutAttributes.lastObject; 217 | contentHeight = lastAttributes.frame.origin.y + lastAttributes.frame.size.height; 218 | _contentSize = CGSizeMake(contentWidth, contentHeight + _itemSpacing); 219 | _itemAttributes = [NSArray arrayWithArray:layoutAttributes]; 220 | } 221 | } 222 | 223 | - (void)prepareHorizontalLayout 224 | { 225 | CGFloat xOffset = _itemSpacing; 226 | CGFloat yOffset = _itemSpacing; 227 | CGFloat columnWidth = 0.0f; 228 | CGFloat contentWidth = 0.0f; 229 | CGFloat contentHeight = 0.0f; 230 | NSUInteger row = 0; 231 | NSInteger numberOfItems = self.numberOfItemsInCollectionView; 232 | NSMutableArray *layoutAttributes = [[NSMutableArray alloc] init]; 233 | 234 | for (int i = 0; i < numberOfItems; i++) 235 | { 236 | CGFloat itemHeight = 0.0f; 237 | 238 | // calculate item size. extra items will have different heights 239 | if (_stretchesLastItems && _extraIndexes.count && [_extraIndexes containsIndex:i]) 240 | { 241 | CGFloat availableSpaceForItems = self.collectionView.bounds.size.height - (2 * _itemSpacing) - ((_extraIndexes.count - 1) * _itemSpacing); 242 | itemHeight = availableSpaceForItems / _extraIndexes.count; 243 | } 244 | else 245 | { 246 | CGFloat availableSpaceForItems = self.collectionView.bounds.size.height - (2 * _itemSpacing) - ((_numberOfItemsInSide - 1) * _itemSpacing); 247 | itemHeight = availableSpaceForItems / _numberOfItemsInSide; 248 | } 249 | 250 | // by default, item height is equal to item width 251 | // if not setting default item height 252 | if (!_itemLength) { 253 | _itemLength = itemHeight; 254 | } 255 | CGSize itemSize = CGSizeMake(_itemLength, itemHeight); 256 | 257 | if (itemSize.width > columnWidth) { 258 | columnWidth = itemSize.width; 259 | } 260 | 261 | // create layout attributes objects 262 | NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0]; 263 | UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath]; 264 | attributes.frame = CGRectIntegral(CGRectMake(xOffset, yOffset, itemSize.width, itemSize.height)); 265 | [layoutAttributes addObject:attributes]; 266 | 267 | // move 'y' for next item 268 | yOffset = yOffset + itemSize.height + _itemSpacing; 269 | row++; 270 | 271 | // if item was the last one in current column 272 | // special case handled for when number of items is lesser than 273 | // number of items in row 274 | if ((numberOfItems < _numberOfItemsInSide && row == numberOfItems) || 275 | (row == _numberOfItemsInSide)) 276 | { 277 | if (xOffset > contentWidth) { 278 | contentWidth = xOffset; 279 | } 280 | 281 | // reset 282 | row = 0; 283 | yOffset = _itemSpacing; 284 | xOffset += columnWidth + _itemSpacing; 285 | } 286 | 287 | // calculate content width 288 | UICollectionViewLayoutAttributes *lastAttributes = layoutAttributes.lastObject; 289 | contentWidth = lastAttributes.frame.origin.x + lastAttributes.frame.size.width; 290 | _contentSize = CGSizeMake(contentWidth + _itemSpacing, contentHeight); 291 | _itemAttributes = [NSArray arrayWithArray:layoutAttributes]; 292 | } 293 | } 294 | 295 | #pragma mark - Property getters 296 | 297 | - (NSInteger)numberOfItemsInCollectionView 298 | { 299 | if (self.collectionView.numberOfSections >0){ 300 | return [self.collectionView numberOfItemsInSection:0]; 301 | }else{ 302 | //Avoid crash if no sections are available 303 | return 0; 304 | } 305 | } 306 | 307 | - (CGSize)collectionViewContentSize 308 | { 309 | return _contentSize; 310 | } 311 | 312 | - (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath 313 | { 314 | return _itemAttributes[indexPath.row]; 315 | } 316 | 317 | - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect 318 | { 319 | NSPredicate *predicate = [NSPredicate predicateWithBlock:^BOOL(UICollectionViewLayoutAttributes *evaluatedObject, NSDictionary *bindings) 320 | { 321 | return CGRectIntersectsRect(rect, evaluatedObject.frame); 322 | }]; 323 | return [_itemAttributes filteredArrayUsingPredicate:predicate]; 324 | } 325 | 326 | #pragma mark - Property setters 327 | 328 | - (void)setNumberOfItemsInSide:(NSInteger)numberOfItemsInSide 329 | { 330 | if (_numberOfItemsInSide != numberOfItemsInSide) 331 | { 332 | _numberOfItemsInSide = numberOfItemsInSide; 333 | [self invalidateLayout]; 334 | } 335 | } 336 | 337 | - (void)setItemLength:(CGFloat)itemLength 338 | { 339 | if (_itemLength != itemLength) 340 | { 341 | _itemLength = itemLength; 342 | [self invalidateLayout]; 343 | } 344 | } 345 | 346 | - (void)setItemSpacing:(CGFloat)itemSpacing 347 | { 348 | if (_itemSpacing != itemSpacing) 349 | { 350 | _itemSpacing = itemSpacing; 351 | [self invalidateLayout]; 352 | } 353 | } 354 | 355 | - (void)setDirection:(ASJCollectionViewFillLayoutDirection)direction 356 | { 357 | if (_direction != direction) 358 | { 359 | _direction = direction; 360 | [self invalidateLayout]; 361 | } 362 | } 363 | 364 | @end 365 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | ## [2.1](https://github.com/sdpjswl/ASJCollectionViewFillLayout/releases/tag/2.1) 4 | Released on Friday, 21 Jan, 2022. 5 | 6 | #### Added 7 | * Merged [pull request #5](https://github.com/sdpjswl/ASJCollectionViewFillLayout/pull/3) that fixes `numberOfItemsInSection` crash. 8 | 9 | ## [2.0](https://github.com/sdpjswl/ASJCollectionViewFillLayout/releases/tag/2.0) 10 | Released on Tuesday, 4 October, 2016. 11 | 12 | This is a major release and breaks things in the old versions. Everyone is recommended to update to version 2.0. 13 | 14 | #### Added 15 | * Added property `direction` to layout items in vertical or horizontal direction. 16 | 17 | #### Changed 18 | * `numberOfItemsInRow` has been renamed to `numberOfItemsInSide`. 19 | * `itemHeight` has been renamed to `itemLength`. 20 | 21 | ## [1.1](https://github.com/sdpjswl/ASJCollectionViewFillLayout/releases/tag/1.1) 22 | Released on Friday, 30 September, 2016. 23 | 24 | #### Added 25 | * Merged [pull request #3](https://github.com/sdpjswl/ASJCollectionViewFillLayout/pull/3) that adds a new property `stretchesLastItems`. 26 | 27 | ## [1.0](https://github.com/sdpjswl/ASJCollectionViewFillLayout/releases/tag/1.0) 28 | Released on Friday, 2 September, 2016. 29 | 30 | #### Added 31 | * Added change log. 32 | * Added orientation support (fixes issue #2). 33 | 34 | #### Fixed 35 | * Fixed a potential bug where it was possible to have a collection view with zero items specified in a row. 36 | * Fixed a UI issue where the bottom-most items would stick to the bottom edge and not be padded. 37 | 38 | ## [0.2](https://github.com/sdpjswl/ASJCollectionViewFillLayout/releases/tag/0.2) 39 | Released on Wednesday, 18 May, 2016. 40 | 41 | #### Added 42 | * Added new screenshots to readme. 43 | * Added credited article's author name to readme. 44 | 45 | #### Fixed 46 | * Minor formatting fixes to readme and code. 47 | 48 | ## [0.1](https://github.com/sdpjswl/ASJCollectionViewFillLayout/releases/tag/0.1) 49 | Released on Wednesday, 11 May, 2016. 50 | 51 | #### Added 52 | * Added nullability annotations. 53 | 54 | #### Updated 55 | * Merged [pull request #1](https://github.com/sdpjswl/ASJCollectionViewFillLayout/pull/1) from ReadmeCritic. 56 | 57 | ## [0.0.2](https://github.com/sdpjswl/ASJCollectionViewFillLayout/releases/tag/0.0.2) 58 | Released on Sunday, 28 Dec, 2015. 59 | 60 | #### Added 61 | * Documentation to the properties. 62 | * Set default item height to the item width if unavailable. 63 | 64 | #### Updated 65 | * Readme to include info about installing from CocoaPods. 66 | 67 | #### Fixed 68 | * Added checks for delegate methods. 69 | 70 | ## [0.0.1](https://github.com/sdpjswl/ASJCollectionViewFillLayout/releases/tag/0.0.1) 71 | Released on Sunday, 20 Dec, 2015. 72 | 73 | #### Added 74 | * Initial release. 75 | -------------------------------------------------------------------------------- /Example/ASJCollectionViewFillLayoutExample.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | C01AE32C1C05DF96006EE67F /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = C01AE32B1C05DF96006EE67F /* main.m */; }; 11 | C01AE32F1C05DF96006EE67F /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = C01AE32E1C05DF96006EE67F /* AppDelegate.m */; }; 12 | C01AE3321C05DF96006EE67F /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C01AE3311C05DF96006EE67F /* ViewController.m */; }; 13 | C01AE3351C05DF96006EE67F /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C01AE3331C05DF96006EE67F /* Main.storyboard */; }; 14 | C01AE3371C05DF96006EE67F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C01AE3361C05DF96006EE67F /* Assets.xcassets */; }; 15 | C01AE33A1C05DF96006EE67F /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C01AE3381C05DF96006EE67F /* LaunchScreen.storyboard */; }; 16 | C0CC18641C2974A4004EDE8D /* ASJCollectionViewFillLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = C0CC18631C2974A4004EDE8D /* ASJCollectionViewFillLayout.m */; }; 17 | /* End PBXBuildFile section */ 18 | 19 | /* Begin PBXFileReference section */ 20 | C01AE3271C05DF96006EE67F /* ASJCollectionViewFillLayoutExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ASJCollectionViewFillLayoutExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; 21 | C01AE32B1C05DF96006EE67F /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 22 | C01AE32D1C05DF96006EE67F /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 23 | C01AE32E1C05DF96006EE67F /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 24 | C01AE3301C05DF96006EE67F /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 25 | C01AE3311C05DF96006EE67F /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 26 | C01AE3341C05DF96006EE67F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 27 | C01AE3361C05DF96006EE67F /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 28 | C01AE3391C05DF96006EE67F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 29 | C01AE33B1C05DF96006EE67F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 30 | C0CC18621C2974A4004EDE8D /* ASJCollectionViewFillLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASJCollectionViewFillLayout.h; sourceTree = ""; }; 31 | C0CC18631C2974A4004EDE8D /* ASJCollectionViewFillLayout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASJCollectionViewFillLayout.m; sourceTree = ""; }; 32 | /* End PBXFileReference section */ 33 | 34 | /* Begin PBXFrameworksBuildPhase section */ 35 | C01AE3241C05DF96006EE67F /* Frameworks */ = { 36 | isa = PBXFrameworksBuildPhase; 37 | buildActionMask = 2147483647; 38 | files = ( 39 | ); 40 | runOnlyForDeploymentPostprocessing = 0; 41 | }; 42 | /* End PBXFrameworksBuildPhase section */ 43 | 44 | /* Begin PBXGroup section */ 45 | C01AE31E1C05DF96006EE67F = { 46 | isa = PBXGroup; 47 | children = ( 48 | C01AE3291C05DF96006EE67F /* ASJCollectionViewFillLayoutExample */, 49 | C01AE3281C05DF96006EE67F /* Products */, 50 | ); 51 | indentWidth = 4; 52 | sourceTree = ""; 53 | tabWidth = 4; 54 | }; 55 | C01AE3281C05DF96006EE67F /* Products */ = { 56 | isa = PBXGroup; 57 | children = ( 58 | C01AE3271C05DF96006EE67F /* ASJCollectionViewFillLayoutExample.app */, 59 | ); 60 | name = Products; 61 | sourceTree = ""; 62 | }; 63 | C01AE3291C05DF96006EE67F /* ASJCollectionViewFillLayoutExample */ = { 64 | isa = PBXGroup; 65 | children = ( 66 | C0CC18611C2974A4004EDE8D /* ASJCollectionViewFillLayout */, 67 | C01AE32D1C05DF96006EE67F /* AppDelegate.h */, 68 | C01AE32E1C05DF96006EE67F /* AppDelegate.m */, 69 | C01AE3301C05DF96006EE67F /* ViewController.h */, 70 | C01AE3311C05DF96006EE67F /* ViewController.m */, 71 | C01AE3331C05DF96006EE67F /* Main.storyboard */, 72 | C01AE3381C05DF96006EE67F /* LaunchScreen.storyboard */, 73 | C01AE3361C05DF96006EE67F /* Assets.xcassets */, 74 | C01AE32A1C05DF96006EE67F /* Supporting Files */, 75 | ); 76 | path = ASJCollectionViewFillLayoutExample; 77 | sourceTree = ""; 78 | }; 79 | C01AE32A1C05DF96006EE67F /* Supporting Files */ = { 80 | isa = PBXGroup; 81 | children = ( 82 | C01AE33B1C05DF96006EE67F /* Info.plist */, 83 | C01AE32B1C05DF96006EE67F /* main.m */, 84 | ); 85 | name = "Supporting Files"; 86 | sourceTree = ""; 87 | }; 88 | C0CC18611C2974A4004EDE8D /* ASJCollectionViewFillLayout */ = { 89 | isa = PBXGroup; 90 | children = ( 91 | C0CC18621C2974A4004EDE8D /* ASJCollectionViewFillLayout.h */, 92 | C0CC18631C2974A4004EDE8D /* ASJCollectionViewFillLayout.m */, 93 | ); 94 | name = ASJCollectionViewFillLayout; 95 | path = ../../ASJCollectionViewFillLayout; 96 | sourceTree = ""; 97 | }; 98 | /* End PBXGroup section */ 99 | 100 | /* Begin PBXNativeTarget section */ 101 | C01AE3261C05DF96006EE67F /* ASJCollectionViewFillLayoutExample */ = { 102 | isa = PBXNativeTarget; 103 | buildConfigurationList = C01AE33E1C05DF96006EE67F /* Build configuration list for PBXNativeTarget "ASJCollectionViewFillLayoutExample" */; 104 | buildPhases = ( 105 | C01AE3231C05DF96006EE67F /* Sources */, 106 | C01AE3241C05DF96006EE67F /* Frameworks */, 107 | C01AE3251C05DF96006EE67F /* Resources */, 108 | ); 109 | buildRules = ( 110 | ); 111 | dependencies = ( 112 | ); 113 | name = ASJCollectionViewFillLayoutExample; 114 | productName = ASJCollectionViewFillLayoutExample; 115 | productReference = C01AE3271C05DF96006EE67F /* ASJCollectionViewFillLayoutExample.app */; 116 | productType = "com.apple.product-type.application"; 117 | }; 118 | /* End PBXNativeTarget section */ 119 | 120 | /* Begin PBXProject section */ 121 | C01AE31F1C05DF96006EE67F /* Project object */ = { 122 | isa = PBXProject; 123 | attributes = { 124 | LastUpgradeCheck = 1320; 125 | ORGANIZATIONNAME = sudeep; 126 | TargetAttributes = { 127 | C01AE3261C05DF96006EE67F = { 128 | CreatedOnToolsVersion = 7.1.1; 129 | }; 130 | }; 131 | }; 132 | buildConfigurationList = C01AE3221C05DF96006EE67F /* Build configuration list for PBXProject "ASJCollectionViewFillLayoutExample" */; 133 | compatibilityVersion = "Xcode 3.2"; 134 | developmentRegion = en; 135 | hasScannedForEncodings = 0; 136 | knownRegions = ( 137 | en, 138 | Base, 139 | ); 140 | mainGroup = C01AE31E1C05DF96006EE67F; 141 | productRefGroup = C01AE3281C05DF96006EE67F /* Products */; 142 | projectDirPath = ""; 143 | projectRoot = ""; 144 | targets = ( 145 | C01AE3261C05DF96006EE67F /* ASJCollectionViewFillLayoutExample */, 146 | ); 147 | }; 148 | /* End PBXProject section */ 149 | 150 | /* Begin PBXResourcesBuildPhase section */ 151 | C01AE3251C05DF96006EE67F /* Resources */ = { 152 | isa = PBXResourcesBuildPhase; 153 | buildActionMask = 2147483647; 154 | files = ( 155 | C01AE33A1C05DF96006EE67F /* LaunchScreen.storyboard in Resources */, 156 | C01AE3371C05DF96006EE67F /* Assets.xcassets in Resources */, 157 | C01AE3351C05DF96006EE67F /* Main.storyboard in Resources */, 158 | ); 159 | runOnlyForDeploymentPostprocessing = 0; 160 | }; 161 | /* End PBXResourcesBuildPhase section */ 162 | 163 | /* Begin PBXSourcesBuildPhase section */ 164 | C01AE3231C05DF96006EE67F /* Sources */ = { 165 | isa = PBXSourcesBuildPhase; 166 | buildActionMask = 2147483647; 167 | files = ( 168 | C01AE3321C05DF96006EE67F /* ViewController.m in Sources */, 169 | C01AE32F1C05DF96006EE67F /* AppDelegate.m in Sources */, 170 | C0CC18641C2974A4004EDE8D /* ASJCollectionViewFillLayout.m in Sources */, 171 | C01AE32C1C05DF96006EE67F /* main.m in Sources */, 172 | ); 173 | runOnlyForDeploymentPostprocessing = 0; 174 | }; 175 | /* End PBXSourcesBuildPhase section */ 176 | 177 | /* Begin PBXVariantGroup section */ 178 | C01AE3331C05DF96006EE67F /* Main.storyboard */ = { 179 | isa = PBXVariantGroup; 180 | children = ( 181 | C01AE3341C05DF96006EE67F /* Base */, 182 | ); 183 | name = Main.storyboard; 184 | sourceTree = ""; 185 | }; 186 | C01AE3381C05DF96006EE67F /* LaunchScreen.storyboard */ = { 187 | isa = PBXVariantGroup; 188 | children = ( 189 | C01AE3391C05DF96006EE67F /* Base */, 190 | ); 191 | name = LaunchScreen.storyboard; 192 | sourceTree = ""; 193 | }; 194 | /* End PBXVariantGroup section */ 195 | 196 | /* Begin XCBuildConfiguration section */ 197 | C01AE33C1C05DF96006EE67F /* Debug */ = { 198 | isa = XCBuildConfiguration; 199 | buildSettings = { 200 | ALWAYS_SEARCH_USER_PATHS = NO; 201 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 202 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 203 | CLANG_CXX_LIBRARY = "libc++"; 204 | CLANG_ENABLE_MODULES = YES; 205 | CLANG_ENABLE_OBJC_ARC = YES; 206 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 207 | CLANG_WARN_BOOL_CONVERSION = YES; 208 | CLANG_WARN_COMMA = YES; 209 | CLANG_WARN_CONSTANT_CONVERSION = YES; 210 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 211 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 212 | CLANG_WARN_EMPTY_BODY = YES; 213 | CLANG_WARN_ENUM_CONVERSION = YES; 214 | CLANG_WARN_INFINITE_RECURSION = YES; 215 | CLANG_WARN_INT_CONVERSION = YES; 216 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 217 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 218 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 219 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 220 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 221 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 222 | CLANG_WARN_STRICT_PROTOTYPES = YES; 223 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 224 | CLANG_WARN_UNREACHABLE_CODE = YES; 225 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 226 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 227 | COPY_PHASE_STRIP = NO; 228 | DEBUG_INFORMATION_FORMAT = dwarf; 229 | ENABLE_STRICT_OBJC_MSGSEND = YES; 230 | ENABLE_TESTABILITY = YES; 231 | GCC_C_LANGUAGE_STANDARD = gnu99; 232 | GCC_DYNAMIC_NO_PIC = NO; 233 | GCC_NO_COMMON_BLOCKS = YES; 234 | GCC_OPTIMIZATION_LEVEL = 0; 235 | GCC_PREPROCESSOR_DEFINITIONS = ( 236 | "DEBUG=1", 237 | "$(inherited)", 238 | ); 239 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 240 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 241 | GCC_WARN_UNDECLARED_SELECTOR = YES; 242 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 243 | GCC_WARN_UNUSED_FUNCTION = YES; 244 | GCC_WARN_UNUSED_VARIABLE = YES; 245 | IPHONEOS_DEPLOYMENT_TARGET = 12.0; 246 | MTL_ENABLE_DEBUG_INFO = YES; 247 | ONLY_ACTIVE_ARCH = YES; 248 | SDKROOT = iphoneos; 249 | }; 250 | name = Debug; 251 | }; 252 | C01AE33D1C05DF96006EE67F /* Release */ = { 253 | isa = XCBuildConfiguration; 254 | buildSettings = { 255 | ALWAYS_SEARCH_USER_PATHS = NO; 256 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 257 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 258 | CLANG_CXX_LIBRARY = "libc++"; 259 | CLANG_ENABLE_MODULES = YES; 260 | CLANG_ENABLE_OBJC_ARC = YES; 261 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 262 | CLANG_WARN_BOOL_CONVERSION = YES; 263 | CLANG_WARN_COMMA = YES; 264 | CLANG_WARN_CONSTANT_CONVERSION = YES; 265 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 266 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 267 | CLANG_WARN_EMPTY_BODY = YES; 268 | CLANG_WARN_ENUM_CONVERSION = YES; 269 | CLANG_WARN_INFINITE_RECURSION = YES; 270 | CLANG_WARN_INT_CONVERSION = YES; 271 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 272 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 273 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 274 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 275 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 276 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 277 | CLANG_WARN_STRICT_PROTOTYPES = YES; 278 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 279 | CLANG_WARN_UNREACHABLE_CODE = YES; 280 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 281 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 282 | COPY_PHASE_STRIP = NO; 283 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 284 | ENABLE_NS_ASSERTIONS = NO; 285 | ENABLE_STRICT_OBJC_MSGSEND = YES; 286 | GCC_C_LANGUAGE_STANDARD = gnu99; 287 | GCC_NO_COMMON_BLOCKS = YES; 288 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 289 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 290 | GCC_WARN_UNDECLARED_SELECTOR = YES; 291 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 292 | GCC_WARN_UNUSED_FUNCTION = YES; 293 | GCC_WARN_UNUSED_VARIABLE = YES; 294 | IPHONEOS_DEPLOYMENT_TARGET = 12.0; 295 | MTL_ENABLE_DEBUG_INFO = NO; 296 | SDKROOT = iphoneos; 297 | VALIDATE_PRODUCT = YES; 298 | }; 299 | name = Release; 300 | }; 301 | C01AE33F1C05DF96006EE67F /* Debug */ = { 302 | isa = XCBuildConfiguration; 303 | buildSettings = { 304 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 305 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = ""; 306 | INFOPLIST_FILE = ASJCollectionViewFillLayoutExample/Info.plist; 307 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 308 | PRODUCT_BUNDLE_IDENTIFIER = com.sudeep.ASJCollectionViewFillLayoutExample; 309 | PRODUCT_NAME = "$(TARGET_NAME)"; 310 | }; 311 | name = Debug; 312 | }; 313 | C01AE3401C05DF96006EE67F /* Release */ = { 314 | isa = XCBuildConfiguration; 315 | buildSettings = { 316 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 317 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = ""; 318 | INFOPLIST_FILE = ASJCollectionViewFillLayoutExample/Info.plist; 319 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 320 | PRODUCT_BUNDLE_IDENTIFIER = com.sudeep.ASJCollectionViewFillLayoutExample; 321 | PRODUCT_NAME = "$(TARGET_NAME)"; 322 | }; 323 | name = Release; 324 | }; 325 | /* End XCBuildConfiguration section */ 326 | 327 | /* Begin XCConfigurationList section */ 328 | C01AE3221C05DF96006EE67F /* Build configuration list for PBXProject "ASJCollectionViewFillLayoutExample" */ = { 329 | isa = XCConfigurationList; 330 | buildConfigurations = ( 331 | C01AE33C1C05DF96006EE67F /* Debug */, 332 | C01AE33D1C05DF96006EE67F /* Release */, 333 | ); 334 | defaultConfigurationIsVisible = 0; 335 | defaultConfigurationName = Release; 336 | }; 337 | C01AE33E1C05DF96006EE67F /* Build configuration list for PBXNativeTarget "ASJCollectionViewFillLayoutExample" */ = { 338 | isa = XCConfigurationList; 339 | buildConfigurations = ( 340 | C01AE33F1C05DF96006EE67F /* Debug */, 341 | C01AE3401C05DF96006EE67F /* Release */, 342 | ); 343 | defaultConfigurationIsVisible = 0; 344 | defaultConfigurationName = Release; 345 | }; 346 | /* End XCConfigurationList section */ 347 | }; 348 | rootObject = C01AE31F1C05DF96006EE67F /* Project object */; 349 | } 350 | -------------------------------------------------------------------------------- /Example/ASJCollectionViewFillLayoutExample.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Example/ASJCollectionViewFillLayoutExample/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // ASJCollectionViewFillLayoutExample 4 | // 5 | // Created by sudeep on 25/11/15. 6 | // Copyright © 2015 sudeep. 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 | -------------------------------------------------------------------------------- /Example/ASJCollectionViewFillLayoutExample/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // ASJCollectionViewFillLayoutExample 4 | // 5 | // Created by sudeep on 25/11/15. 6 | // Copyright © 2015 sudeep. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @interface AppDelegate () 12 | 13 | @end 14 | 15 | @implementation AppDelegate 16 | 17 | 18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 19 | // Override point for customization after application launch. 20 | return YES; 21 | } 22 | 23 | - (void)applicationWillResignActive:(UIApplication *)application { 24 | // 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. 25 | // 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. 26 | } 27 | 28 | - (void)applicationDidEnterBackground:(UIApplication *)application { 29 | // 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. 30 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 31 | } 32 | 33 | - (void)applicationWillEnterForeground:(UIApplication *)application { 34 | // 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. 35 | } 36 | 37 | - (void)applicationDidBecomeActive:(UIApplication *)application { 38 | // 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. 39 | } 40 | 41 | - (void)applicationWillTerminate:(UIApplication *)application { 42 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 43 | } 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /Example/ASJCollectionViewFillLayoutExample/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "scale" : "2x", 6 | "size" : "20x20" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "scale" : "3x", 11 | "size" : "20x20" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "scale" : "2x", 16 | "size" : "29x29" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "scale" : "3x", 21 | "size" : "29x29" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "scale" : "2x", 26 | "size" : "40x40" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "scale" : "3x", 31 | "size" : "40x40" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "scale" : "2x", 36 | "size" : "60x60" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "scale" : "3x", 41 | "size" : "60x60" 42 | }, 43 | { 44 | "idiom" : "ios-marketing", 45 | "scale" : "1x", 46 | "size" : "1024x1024" 47 | } 48 | ], 49 | "info" : { 50 | "author" : "xcode", 51 | "version" : 1 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Example/ASJCollectionViewFillLayoutExample/Assets.xcassets/Brand Assets.launchimage/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "extent" : "full-screen", 5 | "idiom" : "iphone", 6 | "subtype" : "736h", 7 | "filename" : "splash-1242-2208.png", 8 | "minimum-system-version" : "8.0", 9 | "orientation" : "portrait", 10 | "scale" : "3x" 11 | }, 12 | { 13 | "extent" : "full-screen", 14 | "idiom" : "iphone", 15 | "subtype" : "667h", 16 | "filename" : "splash-750-1334.png", 17 | "minimum-system-version" : "8.0", 18 | "orientation" : "portrait", 19 | "scale" : "2x" 20 | }, 21 | { 22 | "orientation" : "portrait", 23 | "idiom" : "iphone", 24 | "filename" : "splash-640-960.png", 25 | "extent" : "full-screen", 26 | "minimum-system-version" : "7.0", 27 | "scale" : "2x" 28 | }, 29 | { 30 | "extent" : "full-screen", 31 | "idiom" : "iphone", 32 | "subtype" : "retina4", 33 | "filename" : "splash-640-1136.png", 34 | "minimum-system-version" : "7.0", 35 | "orientation" : "portrait", 36 | "scale" : "2x" 37 | } 38 | ], 39 | "info" : { 40 | "version" : 1, 41 | "author" : "xcode" 42 | } 43 | } -------------------------------------------------------------------------------- /Example/ASJCollectionViewFillLayoutExample/Assets.xcassets/Brand Assets.launchimage/splash-1242-2208.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdpjswl/ASJCollectionViewFillLayout/972a9da910a1b06ed95d3ab5cfba85beae7bca3b/Example/ASJCollectionViewFillLayoutExample/Assets.xcassets/Brand Assets.launchimage/splash-1242-2208.png -------------------------------------------------------------------------------- /Example/ASJCollectionViewFillLayoutExample/Assets.xcassets/Brand Assets.launchimage/splash-640-1136.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdpjswl/ASJCollectionViewFillLayout/972a9da910a1b06ed95d3ab5cfba85beae7bca3b/Example/ASJCollectionViewFillLayoutExample/Assets.xcassets/Brand Assets.launchimage/splash-640-1136.png -------------------------------------------------------------------------------- /Example/ASJCollectionViewFillLayoutExample/Assets.xcassets/Brand Assets.launchimage/splash-640-960.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdpjswl/ASJCollectionViewFillLayout/972a9da910a1b06ed95d3ab5cfba85beae7bca3b/Example/ASJCollectionViewFillLayoutExample/Assets.xcassets/Brand Assets.launchimage/splash-640-960.png -------------------------------------------------------------------------------- /Example/ASJCollectionViewFillLayoutExample/Assets.xcassets/Brand Assets.launchimage/splash-750-1334.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdpjswl/ASJCollectionViewFillLayout/972a9da910a1b06ed95d3ab5cfba85beae7bca3b/Example/ASJCollectionViewFillLayoutExample/Assets.xcassets/Brand Assets.launchimage/splash-750-1334.png -------------------------------------------------------------------------------- /Example/ASJCollectionViewFillLayoutExample/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Example/ASJCollectionViewFillLayoutExample/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /Example/ASJCollectionViewFillLayoutExample/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 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 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | -------------------------------------------------------------------------------- /Example/ASJCollectionViewFillLayoutExample/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 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 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeRight 37 | UIInterfaceOrientationLandscapeLeft 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /Example/ASJCollectionViewFillLayoutExample/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // ASJCollectionViewFillLayoutExample 4 | // 5 | // Created by sudeep on 25/11/15. 6 | // Copyright © 2015 sudeep. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /Example/ASJCollectionViewFillLayoutExample/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // ASJCollectionViewFillLayoutExample 4 | // 5 | // Created by sudeep on 25/11/15. 6 | // Copyright © 2015 sudeep. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | #import "ASJCollectionViewFillLayout.h" 11 | 12 | static NSInteger const kNoOfItems = 17; 13 | static NSString *const reuseIdentifier = @"cell"; 14 | 15 | @interface ViewController () 16 | 17 | @property (weak, nonatomic) IBOutlet UICollectionView *aCollectionView; 18 | @property (strong, nonatomic) ASJCollectionViewFillLayout *aLayout; 19 | @property (copy, nonatomic) NSArray *objects; 20 | @property (weak, nonatomic) IBOutlet UISegmentedControl *directionSegmentedControl; 21 | 22 | - (void)setup; 23 | - (void)setupCollectionViewData; 24 | - (void)setupLayout; 25 | - (IBAction)directionChanged:(id)sender; 26 | 27 | @end 28 | 29 | @implementation ViewController 30 | 31 | - (void)viewDidLoad 32 | { 33 | [super viewDidLoad]; 34 | [self setup]; 35 | } 36 | 37 | #pragma mark - Setup 38 | 39 | - (void)setup 40 | { 41 | [self setupCollectionViewData]; 42 | [self setupLayout]; 43 | } 44 | 45 | - (void)setupLayout 46 | { 47 | _aLayout = [[ASJCollectionViewFillLayout alloc] init]; 48 | _aLayout.delegate = self; 49 | _aLayout.direction = ASJCollectionViewFillLayoutVertical; 50 | _aCollectionView.collectionViewLayout = _aLayout; 51 | } 52 | 53 | - (void)setupCollectionViewData 54 | { 55 | NSMutableArray *temp = [[NSMutableArray alloc] init]; 56 | for (int i=0; i 70 | 71 | - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section 72 | { 73 | return _objects.count; 74 | } 75 | 76 | - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath 77 | { 78 | UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:reuseIdentifier forIndexPath:indexPath]; 79 | cell.backgroundColor = [[UIColor redColor] colorWithAlphaComponent:0.5]; 80 | UILabel *lbl = (UILabel *)[cell viewWithTag:1]; 81 | lbl.text = _objects[indexPath.row]; 82 | return cell; 83 | } 84 | 85 | #pragma mark 86 | 87 | - (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath 88 | { 89 | NSString *message = [NSString stringWithFormat:@"Item %ld tapped", (long)indexPath.row + 1]; 90 | UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Tap" message:message preferredStyle:UIAlertControllerStyleAlert]; 91 | UIAlertAction *ok = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil]; 92 | [alert addAction:ok]; 93 | [self presentViewController:alert animated:YES completion:nil]; 94 | } 95 | 96 | #pragma mark - ASJCollectionViewFillLayoutDelegate 97 | 98 | - (NSInteger)numberOfItemsInSide 99 | { 100 | return 3; 101 | } 102 | 103 | - (CGFloat)itemLength 104 | { 105 | return 100.0f; 106 | } 107 | 108 | - (CGFloat)itemSpacing 109 | { 110 | return 5.0f; 111 | } 112 | 113 | @end 114 | -------------------------------------------------------------------------------- /Example/ASJCollectionViewFillLayoutExample/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // ASJCollectionViewFillLayoutExample 4 | // 5 | // Created by sudeep on 25/11/15. 6 | // Copyright © 2015 sudeep. 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 | -------------------------------------------------------------------------------- /Images/7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdpjswl/ASJCollectionViewFillLayout/972a9da910a1b06ed95d3ab5cfba85beae7bca3b/Images/7.png -------------------------------------------------------------------------------- /Images/8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdpjswl/ASJCollectionViewFillLayout/972a9da910a1b06ed95d3ab5cfba85beae7bca3b/Images/8.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Sudeep Jaiswal 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ASJCollectionViewFillLayout 2 | 3 | The standard available `UICollectionViewLayout` does the job well, but the UI may look asymmetric, depending on the number of items the `UICollectionView` is displaying. This library attempts to solve this problem. This is a `UICollectionViewLayout` subclass that fills the full width of the collection view. 4 | 5 | # Installation 6 | 7 | CocoaPods is the preferred way to install this library. Add this command to your `Podfile`: 8 | 9 | ```ruby 10 | pod 'ASJCollectionViewFillLayout' 11 | ``` 12 | 13 | If you prefer the classic way, just copy the `ASJCollectionViewFillLayout` folder (.h and .m files) to your project. 14 | 15 | # Usage 16 | 17 | Creating an `ASJCollectionViewFillLayout` is easy. It has a simple interface consisting of three properties. You can also use the traditional delegate pattern to return the attributes you wish to use. All are optional. 18 | 19 | ```objc 20 | @property (assign, nonatomic) NSInteger numberOfItemsInSide; 21 | ``` 22 | Sets the number of items to show in one row or column, depending on the layout's `direction` property. 23 | 24 | ```objc 25 | @property (assign, nonatomic) CGFloat itemLength; 26 | ``` 27 | Sets the width or height of an item, depending on the layout's `direction` property. For vertical direction, this sets the item height and for horizontal direction, this sets the item width. 28 | 29 | ```objc 30 | @property (assign, nonatomic) CGFloat itemSpacing; 31 | ``` 32 | Sets the distance between two collection view items. 33 | 34 | ```objc 35 | @property (assign, nonatomic) ASJCollectionViewFillLayoutDirection direction; 36 | ``` 37 | Sets the direction in which the collection view items are laid out. Valid options are `ASJCollectionViewFillLayoutVertical` and `ASJCollectionViewFillLayoutHorizontal`. Defaults to `ASJCollectionViewFillLayoutVertical`. 38 | 39 | ```objc 40 | @property (assign, nonatomic) BOOL stretchesLastItems; 41 | ``` 42 | Sets whether the last items should be stretched to occupy the full width of the `UICollectionView`. Defaults to `YES`. 43 | 44 | For example: 45 | 46 | ```objc 47 | ASJCollectionViewFillLayout *aFillLayout = [[ASJCollectionViewFillLayout alloc] init]; 48 | aFillLayout.numberOfItemsInSide = 3; 49 | aFillLayout.itemSpacing = 5.0f; 50 | aFillLayout.itemLength = 75.0f; 51 | aFillLayout.stretchesLastItems = NO; 52 | aCollectionView.collectionViewLayout = aFillLayout; 53 | ``` 54 | 55 | See the example project for a demonstration of how to use the delegate pattern. 56 | 57 | ![alt tag](Images/7.png) 58 | ![alt tag](Images/8.png) 59 | 60 | # Credits 61 | 62 | - Damir Tursunovic - [Implementing UICollectionViewLayout](http://damir.me/implementing-uicollectionview-layout) 63 | - [Oggerschummer](https://github.com/Oggerschummer) for adding `stretchesLastItems` property 64 | 65 | # To-do 66 | 67 | - ~~Handle case of total collection view items being less than the number of items in one row.~~ 68 | - ~~Add option for horizontal direction; try subclassing `UICollectionViewFlowLayout` itself.~~ 69 | 70 | # License 71 | 72 | `ASJCollectionViewFillLayout` is available under the MIT license. See the LICENSE file for more info. 73 | --------------------------------------------------------------------------------