iOS: UICollectionView repeat NSMutableArray value in circular way - ios

How can I repeat NSMutableArray value in UICollectionView and scroll automatically from top to bottom for gaming like effect?
For example if I have array with 10 elements and wants to repeat all 10 value in UICollectionView with 4 cells in a row and scroll from top to bottom continuously.
Currently I am adding 200 values statically in NSMutableArray and than applying NSTimer on that. But I want to repeat 10 values again and again.
How can I do that?
code given below is to call on NSTimer for scrolling
[collectionview setUserInteractionEnabled:NO];
CGFloat h = collectionview.contentOffset.y;
h += 10;
CGFloat h2 = 10;
h2 += 10;
CGPoint bottomOffset = CGPointMake(0, h - h2);
[collectionview setContentOffset:bottomOffset animated:YES];
int dd = collectionview.contentOffset.y;
NSLog(#"dd timer....%d" ,dd);
if (dd <= 0) {
}

I have a similar situation where I continuously scroll a collection of images. What I did was in collectionView:numberOfItemsInSection: was return INT_MAX. Then in collectionView:cellForItemAtIndexPath:, just mod the row by the size of your NSMutableArray and use that as the index into your array to create the UICollectionViewCell. It doesn't scroll backwards from the top of the list, and it isn't exactly "infinite", but it sure does provied a LOT of cells. I suppose if you wanted to start in the middle and allow scrolling backwards, you could just scroll the collection view to some cell that makes sense in the middle of the collection.
Example implementation:
#interface CollectionViewController ()
#property (nonatomic, strong) NSArray<NSString*>* objects;
#end
#implementation CollectionViewController
static NSString * const reuseIdentifier = #"Cell";
- (void)viewDidLoad
{
[super viewDidLoad];
_objects = #[#"One", #"Two", #"Three", #"Four", #"Five", #"Six", #"Seven", #"Eight", #"Nine", #"Ten"];
}
#pragma mark <UICollectionViewDataSource>
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
return 1;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return INT_MAX;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
CollectionViewCell* cell = (CollectionViewCell*)[collectionView dequeueReusableCellWithReuseIdentifier:reuseIdentifier forIndexPath:indexPath];
NSInteger index = indexPath.row % self.objects.count;
NSString* str = self.objects[index];
[cell.label setText:str];
return cell;
}
#end
I don't know for sure what the performance impact of this is, but since UICollectionView only loads as many cells as it needs, I don't believe it to be too impactful. It works well for me.
If true circular scrolling is important, you could try an open-source solution (ex. https://cocoapods.org/pods/PMCircularCollectionView)

You can try this:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView_
{
CGFloat actualPosition = scrollView_.contentOffset.y;
CGFloat contentHeight = scrollView_.contentSize.height - (someArbitraryNumber);
if (actualPosition >= contentHeight) {
[yourMutableArray addObjectsFromArray: yourMutableArray];
[yourCollectionView reloadData];
}
}

Related

How can I create Infinite Scrolling in UICollectionView for iOS Objective-c

How To Create Infinite Scrolling in my UICollectionView?
attached screenshot :
Now my NSArray is
NSArray* nameArr = [NSArray arrayWithObjects: #"0", #"1", #"2", #"3", #"4", nil];
I want to create an Infinite Scrolling in collectionView After Complete array repeat all cells again and again.
Left and Right both side required to scroll Infinite.
If yes, then how can I implement please give a reference in objective-c.
Thanks!!! In advance
The simple way is using StableCollectionViewLayout.
The basic principle of implementation is creating a subclass of UICollectionViewLayout and overriding these methods
override open func prepare(forCollectionViewUpdates updateItems: [UICollectionViewUpdateItem]) {
super.prepare(forCollectionViewUpdates: updateItems)
// there is possible to calculate a content offset the difference
// with the help layout attributes for each updated item or only visible items
self.offset = calculate(...)
}
override open func finalizeCollectionViewUpdates() {
super.finalizeCollectionViewUpdates()
self.offset = nil
}
override open func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint) -> CGPoint {
// there is necessary to add difference to/instead proposedContentOffset
if let offset = self.offset {
return offset
}
return proposedContentOffset
}
It allows keeping content offset when inserting or deleting happens.
Then you can just insert at the head and delete the tail, or vice versa.
First thing replace your current NSArray with NSMutableArray and make this changes as above in your cellForItemAtIndexPath
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return nameArr.count;
}
- (__kindof UICollectionViewCell *) collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"Cell" forIndexPath:indexPath];
UILabel *label = [cell viewWithTag:25];
[label setText:[NSString stringWithFormat:#"%ld",(long)indexPath.row]];
if(indexPath.row == nameArr.count-1) {
[nameArr addObjectsFromArray:nameArr.mutableCopy];
[collectionView reloadData];
}
return cell;
}
Here we are adding the same array objects again and again so it will be scroll infinite time.
Attached screenshot: Refer This
Hope this will help you
Had the same problem and i solved it by returning the number of items
in numberOfItemsInSection: by 2
-(NSInteger)collectionView:(UICollectionView *)collectionView
numberOfItemsInSection:(NSInteger)section{
return _array.count * 2;
}
in cellForItemAtIndexPath i return the cell the usual way and if the index is higher than the _array.count the just subtract the _array.count from the index.
-(UICollectionViewCell *)collectionView:(UICollectionView
*)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
NSInteger index = indexPath.item;
if(index > _array.count - 1){
index -= _array.count;
}
CellView *cell = [collectionView
dequeueReusableCellWithReuseIdentifier:#"cellIdentifier"
forIndexPath:indexPath];
//To get the string from the array use
NSString string = [_array objectAtIndex:(index % _array.count)];
return cell;
}
Now the thing about this method is that i use only 2N items in the collectionView instead of a huge random number.
The trick is "put the 2 arrays side by side" and to keep the user in the middle using the offset.
-(void)scrollViewDidScroll:(UIScrollView *)scrollView{
int scrollViewWidth = scrollView.contentSize.width;
CGPoint offset = scrollView.contentOffset;
if(offset.x < scrollViewWidth /4){
offset.x += scrollViewWidth / 2;
[scrollView setContentOffset:offset];
} else if(offset.x > scrollViewWidth /4 *3){
offset.x -= scrollViewWidth / 2;
[scrollView setContentOffset:offset];
}
}

Cell disappears after reloading when using estimatedSize

I'm having a weird issue, when using a collection view with dynamic sizes, this issue doesn't happens while using fixed sizes.
After a reload the first cell of each section disappears, but only if they are out of the screen. After a few tests I realize that the cell didn't disappear, but its hidden bellow the section header.
Do you have any idea what is causing this?
Collection without reloading:
Collection after reloading with cell visible:
Collection after reloading with cell out of screen:
3D view of the cell after reloading:
The code:
#pragma mark - UICollectionViewDataSource
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
return self.sections.count;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)sectionIndex {
Section *section = [self.sections objectAtIndex:sectionIndex];
return section.items.count;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
Section *section = [self.sections objectAtIndex:indexPath.section];
Item *item = [section.items objectAtIndex:indexPath.row];
if (self.editing) {
EditingCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"cell-editing" forIndexPath:indexPath];
cell.item = item;
return cell;
} else {
BasicCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"cell" forIndexPath:indexPath];
cell.item = item;
return cell;
}
}
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath {
if ([kind isEqualToString:UICollectionElementKindSectionHeader]) {
HeaderCollectionReusableView *header = [collectionView dequeueReusableSupplementaryViewOfKind:kind withReuseIdentifier:#"header" forIndexPath:indexPath];
Section *section = [self.sections objectAtIndex:indexPath.section];
header.title = section.title;
return header;
} else {
UICollectionReusableView *footer = [collectionView dequeueReusableSupplementaryViewOfKind:kind withReuseIdentifier:#"footer" forIndexPath:indexPath];
return footer;
}
}
#implementation DetailCollectionViewLayout
- (instancetype)init {
if (self = [super init]) {
[self initialize];
}
return self;
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
if (self = [super initWithCoder:aDecoder]) {
[self initialize];
}
return self;
}
- (void)prepareLayout {
CGFloat cellWidth = (isIPAD) ? 288 : CGRectGetWidth(self.collectionView.bounds);
CGFloat headerWidth = CGRectGetWidth(self.collectionView.bounds);
// CGFloat ratio = (isIPAD) ? 0.33 : 0.66;
self.estimatedItemSize = CGSizeMake(cellWidth, 53);
self.headerReferenceSize = CGSizeMake(headerWidth, 50);
self.footerReferenceSize = CGSizeMake(headerWidth, 1 + self.minimumInteritemSpacing);
[super prepareLayout];
}
- (void)initialize {
self.minimumLineSpacing = 0;
self.minimumInteritemSpacing = (isIPAD) ? 5 : 10;
self.estimatedItemSize = CGSizeZero;
self.scrollDirection = UICollectionViewScrollDirectionVertical;
self.sectionInset = UIEdgeInsetsZero;
}
-(BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds {
return YES;
}
#end
I made a simple sample project and record a video: http://sendvid.com/330uo5jm
It looks like the issue is the position from the first cell.
UICollectionViewCell autosizing can be a little, uh... interesting even at the best of times. I've had this exact issue in the past, and similar issues too.
Use a different value for .estimatedItemSize, the closer to the actual item size the better. I noticed you're using a size of CGRectZero at first. I wouldn't recommend doing that. Just set it once, at the start, with a value close to your size. Try a few values, see what works for you. For me, it took a bit of fine tuning.
For anyone developing for iOS 10 (at the time of writing this hasn't been released) there is a new collection view property that lets the collection view determine the estimated size itself. Set the itemSize to UICollectionViewFlowLayoutAutomaticSize, you shouldn't need to set .estimatedItemSize explicitly.
make sure your estimatedItemSize in your code same as size of cell in your xib or storyboard.Don't changes it's size runtime.
can you check with use of identifier like...
NSString *CellIdentifier = [NSString stringWithFormat:#"%d_%d",indexPath.section,indexPath.row];
Sometimes it happens if you have a big difference between estimated size and real size of cell.
Check you have a clear consequence of top to bottom constraints (if you are using autolayout).
Is there something that can break the autolayout to work properly ? E.g compresion resistance settings ?
Are you sure there are data for the cell after reload ? (Will be weird, but to be sure, just double check that.)
Also as Apple denotes here Apple - self sizing guide try to set the estimation of size as close as possible to real dimensions.
You can also try to refer to invalidation of collection layout as you are using your own. Refer to Possible flow-layout help
Try to set the estimation as close as possible and you will see if it solve your problem.

How do I create a UICollectionView with column and row headers?

I want to create a UICollectionView that looks like this:
It won't be scrollable or editable. I'm currently wondering how to write the layout for this. I'm guessing it won't be a subclass of UICollectionViewFlowLayout. I can think of a number of ways, but was curious if there was any "right" way. The cells will be animate-able.
Should each row or column be its own section?
I've done something like what you want with a subclass of UICollectionViewFlowLayout. It looks like this,
#implementation MultpleLineLayout {
NSInteger itemWidth;
NSInteger itemHeight;
}
-(id)init {
if (self = [super init]) {
itemWidth = 80;
itemHeight = 80;
}
return self;
}
-(CGSize)collectionViewContentSize {
NSInteger xSize = [self.collectionView numberOfItemsInSection:0] * (itemWidth + 2); // the 2 is for spacing between cells.
NSInteger ySize = [self.collectionView numberOfSections] * (itemHeight + 2);
return CGSizeMake(xSize, ySize);
}
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)path {
UICollectionViewLayoutAttributes* attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:path];
NSInteger xValue;
attributes.size = CGSizeMake(itemWidth,itemHeight);
xValue = itemWidth/2 + path.row * (itemWidth +2);
NSInteger yValue = itemHeight + path.section * (itemHeight +2);
attributes.center = CGPointMake(xValue, yValue);
return attributes;
}
-(NSArray*)layoutAttributesForElementsInRect:(CGRect)rect {
NSInteger minRow = (rect.origin.x > 0)? rect.origin.x/(itemWidth +2) : 0; // need to check because bounce gives negative values for x.
NSInteger maxRow = rect.size.width/(itemWidth +2) + minRow;
NSMutableArray* attributes = [NSMutableArray array];
for(NSInteger i=0 ; i < self.collectionView.numberOfSections; i++) {
for (NSInteger j=minRow ; j < maxRow; j++) {
NSIndexPath* indexPath = [NSIndexPath indexPathForItem:j inSection:i];
[attributes addObject:[self layoutAttributesForItemAtIndexPath:indexPath]];
}
}
return attributes;
}
The data is arranged as an array of arrays where each inner array supplies the data for one horizontal row. With the values I have in there now, and using your data as an example, the view looked like this,
This is the code I haven the view controller,
#interface ViewController ()
#property (strong,nonatomic) UICollectionView *collectionView;
#property (strong,nonatomic) NSArray *theData;
#end
#implementation ViewController
- (void)viewDidLoad {
self.theData = #[#[#"",#"A",#"B",#"C"],#[#"1",#"115",#"127",#"132"],#[#"2",#"",#"",#"153"],#[#"3",#"",#"199",#""]];
MultpleLineLayout *layout = [[MultpleLineLayout alloc] init];
self.collectionView = [[UICollectionView alloc] initWithFrame:self.view.bounds collectionViewLayout:layout];
self.collectionView.dataSource = self;
self.collectionView.delegate = self;
layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
self.view.backgroundColor = [UIColor blackColor];
[self.view addSubview:self.collectionView];
[self.collectionView registerNib:[UINib nibWithNibName:#"CustomDataCell" bundle:nil] forCellWithReuseIdentifier:#"DataCell"];
}
- (NSInteger)collectionView:(UICollectionView *)view numberOfItemsInSection:(NSInteger)section {
return [self.theData[section] count];
}
- (NSInteger)numberOfSectionsInCollectionView: (UICollectionView *)collectionView {
return [self.theData count];
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
DataCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"DataCell" forIndexPath:indexPath];
cell.label.text = self.theData[indexPath.section][indexPath.row];
return cell;
}
You can do it with UICollectionViewFlowLayout but if you go that way you need to count carefully and get the padding (i.e. the top left, and other "empty" cells) right. If you miscount it's obvious because the flow ruins everything quickly and you will find your header cells halfway down your columns. (I have done a similar thing)
I only did it that way because of a fear of custom layouts - but in fact it is as easy as UITableView. If your layout does not scroll at all then yours will be particularly simple as your only real work will be calculating frame values for cells, to be returned in layoutAttributesForItemAtIndexPath. Since your whole view fits in the visible area, layoutAttributesForElementsInRect will mean you simply iterate through all the cells in the view. collectionViewContentSize will be the size of your view.
Looking at your sample picture you might find it convenient to organise your data as a dictionary of arrays, one per column. You can get a column array by name ("A", "B" etc.) and the position in the array corresponds to the value in the leftmost column, which you might name "index".
There are many more methods you can use but those are the basics, and will get your basic display up and running.

Animate a UICollectionView cell on selection

I have a basic grid in a UICollectionView. It's a simple 2 column, multiple row layout using the UICollectionViewDelegateFlowLayout. When a cell is selected, I want to dim the background, float the cell to the center of the screen and then have a workflow based on the selected cell. I'm fairly new to UICollectionViews, and I'm not sure of the best way to go about this.
Should I have a custom layout of the UICollectionView for when a cell is selected?
Or is there a way I can animate the selected cell without having to create a new layout
If anyone can just get me going on the right direction, I think I'll be good to research how to execute it.
After trying several (and rather hacky) solutions, I solved this by writing my own UICollectionView layout. Previous solutions I attempted:
Add a custom UIView overtop the UICollectionView and attempt to fake the original cell moving by overlaying it, dimming the background, and animating the new UIView
Animate the cell without creating a brand new layout
I was trying to avoid it, but after I got into coding it, it was a lot less painful than I originally thought.
Here is my code, for anyone interested:
.h:
#interface FMStackedLayout : UICollectionViewLayout
#property(nonatomic,assign) CGPoint center;
#property(nonatomic,assign) NSInteger cellCount;
-(id)initWithSelectedCellIndexPath:(NSIndexPath *)indexPath;
#end
.m:
#define ITEM_WIDTH 128.0f
#define ITEM_HEIGHT 180.0f
static NSUInteger const RotationCount = 32;
static NSUInteger const RotationStride = 3;
static NSUInteger const PhotoCellBaseZIndex = 100;
#interface FMStackedLayout ()
#property(strong,nonatomic) NSArray *rotations;
#property(strong,nonatomic) NSIndexPath *selectedIndexPath;
#end
#implementation FMStackedLayout
#pragma mark - Lifecycle
-(id)initWithSelectedCellIndexPath:(NSIndexPath *)indexPath{
self = [super init];
if (self) {
self.selectedIndexPath = indexPath;
[self setup];
}
return self;
}
-(id)initWithCoder:(NSCoder *)aDecoder{
self = [super init];
if (self){
[self setup];
}
return self;
}
-(void)setup{
NSMutableArray *rotations = [NSMutableArray arrayWithCapacity:RotationCount];
CGFloat percentage = 0.0f;
for (NSUInteger i = 0; i < RotationCount; i++) {
// Ensure that each angle is different enough to be seen
CGFloat newPercentage = 0.0f;
do {
newPercentage = ((CGFloat)(arc4random() % 220) - 110) * 0.0001f;
} while (fabsf(percentage - newPercentage) < 0.006);
percentage = newPercentage;
CGFloat angle = 2 * M_PI * (1.0f + percentage);
CATransform3D transform = CATransform3DMakeRotation(angle, 0.0f, 0.0f, 1.0f);
[rotations addObject:[NSValue valueWithCATransform3D:transform]];
}
self.rotations = rotations;
}
#pragma mark - Layout
-(void)prepareLayout{
[super prepareLayout];
CGSize size = self.collectionView.frame.size;
self.cellCount = [self.collectionView numberOfItemsInSection:0];
self.center = CGPointMake(size.width / 2.0, size.height / 2.0);
}
-(CGSize)collectionViewContentSize{
return self.collectionView.frame.size;
}
-(UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath{
UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
attributes.size = CGSizeMake(ITEM_WIDTH, ITEM_HEIGHT);
attributes.center = self.center;
if (indexPath.item == self.selectedIndexPath.item) {
attributes.zIndex = 100;
}else{
attributes.transform3D = [self transformForPersonViewAtIndex:indexPath];
}
return attributes;
}
-(NSArray *)layoutAttributesForElementsInRect:(CGRect)rect{
NSMutableArray *attributes = [NSMutableArray array];
for (NSInteger i = 0; i < self.cellCount; i++) {
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i
inSection:0];
[attributes addObject:[self layoutAttributesForItemAtIndexPath:indexPath]];
}
return attributes;
}
#pragma mark - Private
-(CATransform3D)transformForPersonViewAtIndex:(NSIndexPath *)indexPath{
NSInteger offset = (indexPath.section * RotationStride + indexPath.item);
return [self.rotations[offset % RotationCount] CATransform3DValue];
}
#end
Then, on your UICollectionView, you call
MyLayout *stackedLayout = [[MyLayout alloc] initWithSelectedCellIndexPath:indexPath];
[stackedLayout invalidateLayout];
[self.collectionView setCollectionViewLayout:stackedLayout
animated:YES];
Animations between cells will be handled by the custom layout.
Seems to be a multi-part question, so I'll answer part of it.
UICollectionviewCells do not automatically adjust on highlight or selection. It will only tell you when the cell is highlighted or selected, with one exception:
For the most part, the collection view modifies only the properties of
a cell to indicate that it is selected or highlighted; it does not
change the visual appearance of your cells, with one exception. If a
cell’s selectedBackgroundView property contains a valid view, the
collection view shows that view when the cell is highlighted or
selected.
Otherwise, you must do the visual highlighting manually. Usually by adjusting either the .alpha property of the entire cell, or swapping out the .image property of a background UIImageView in the cell itself using one or more of the following methods, which are accessible in the <UICollectionViewDelegate> Protocol:
collectionView:didDeselectItemAtIndexPath:
collectionView:didHighlightItemAtIndexPath:
collectionView:didSelectItemAtIndexPath:
collectionView:didUnhighlightItemAtIndexPath:
collectionView:shouldDeselectItemAtIndexPath:
collectionView:shouldHighlightItemAtIndexPath:
collectionView:shouldSelectItemAtIndexPath:
As for the rest of your question,I wish I could be of more help, but I'm not as fluent at the custom view animation.

Subclassing UICollectionViewLayout and assign to UICollectionView

I have a CollectionViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// assign layout (subclassed below)
self.collectionView.collectionViewLayout = [[CustomCollectionLayout alloc] init];
}
// data source is working, here's what matters:
- (UICollectionViewCell *)collectionView:(UICollectionView *)cv cellForItemAtIndexPath:(NSIndexPath *)indexPath {
ThumbCell *cell = (ThumbCell *)[cv dequeueReusableCellWithReuseIdentifier:#"ThumbCell" forIndexPath:indexPath];
return cell;
}
I also have a UICollectionViewLayout subclass: CustomCollectionLayout.m
#pragma mark - Overriden methods
- (CGSize)collectionViewContentSize
{
return CGSizeMake(320, 480);
}
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
return [[super layoutAttributesForElementsInRect:rect] mutableCopy];
}
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
{
// configure CellAttributes
cellAttributes = [super layoutAttributesForItemAtIndexPath:indexPath];
// random position
int xRand = arc4random() % 320;
int yRand = arc4random() % 460;
cellAttributes.frame = CGRectMake(xRand, yRand, 150, 170);
return cellAttributes;
}
I'm trying to use a new frame for the cell, just one at a random position.
The problem is layoutAttributesForItemAtIndexPath is not called.
Thanks in advance for any advice.
Edit: I didn't notice that you've solved your case, but I had the same problem and here's what helped in my case. I'm leaving it here, it may be useful for someone given that there's not much on this topic yet.
Upon drawing, UICollectionView does not call the method layoutAttributesForItemAtIndexPath: but layoutAttributesForElementsInRect: to determine which cells should be visible. It's your responsibility to implement this method and from there call layoutAttributesForItemAtIndexPath: for all visible index paths to determine exact locations.
In other words, add this to your layout:
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
NSMutableArray * array = [NSMutableArray arrayWithCapacity:16];
// Determine visible index paths
for(???) {
[array addObject:[self layoutAttributesForItemAtIndexPath:[NSIndexPath indexPathForItem:??? inSection:???]]];
}
return [array copy];
}
Was an issue with Storyboard parameters. Assigned custom UICollectionLayout from Inspector panel.

Resources