Add more images to an already running UICollectionView - ios

I have a UICollectionView that i set up in the viewDidLoad and add the images immediately after that. When the user scrolls to a certain point i try to add more images but The collection view won't load the new images
How do i reload or add more images to my scrollview
#pragma mark - New Retrieve
- (void) rwDataToPlist {
// Step1: Get plist file path
NSArray *sysPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory ,NSUserDomainMask, YES);
NSString *documentsDirectory = [sysPaths objectAtIndex:0];
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:#"news.plist"];
NSLog(#"Plist File Path: %#", filePath);
if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
stuff = [[NSArray alloc] initWithContentsOfFile:filePath];
//NSLog(#"Stuff %#", stuff);
[self sortRetrievedData];
} else {
}
}
-(void)sortRetrievedData {
titles = [stuff valueForKey:kKeyTitle];
thumbMediaUrl = [stuff valueForKey:kKeyThumbUrl];
thumbWidth = [stuff valueForKey:kKeyThumbWidth];
thumbHeight = [stuff valueForKey:kKeyThumbHeight];
for(NSArray *array in titles) {
for (NSArray *realArray in array) {
titles = realArray;
}
}
for(NSArray *array in thumbMediaUrl) {
for(NSDictionary *dict in array) {
thumbMediaUrl = dict;
}
}
for(NSArray *array in thumbWidth) {
for(NSDictionary *dict in array) {
thumbWidth = dict;
}
}
for(NSArray *array in thumbHeight) {
for(NSDictionary *dict in array) {
thumbHeight = dict;
}
}
}
#pragma mark - Collection View
#pragma mark - Display Collection
-(void)displayCollection {
UIColor *myColor = [UIColor colorWithRed:(245.0 / 255.0) green:(245.0 / 255.0) blue:(245.0 / 255.0) alpha: 1];
CGRect screenBound = [[UIScreen mainScreen] bounds];
CGSize screenSize = screenBound.size;
CGFloat screenWidth = screenSize.width;
CGFloat screenHeight = screenSize.height;
self.view = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
CGRect locOfScree = CGRectMake(0, 64, screenWidth, screenHeight - 44);
UICollectionViewFlowLayout *layout=[[UICollectionViewFlowLayout alloc] init];
imageDisplayer = [[UICollectionView alloc] initWithFrame:locOfScree collectionViewLayout:layout];
[imageDisplayer setDataSource:self];
[imageDisplayer setDelegate:self];
UINib *nib = [UINib nibWithNibName:#"CollectionViewCell" bundle:nil];
[imageDisplayer registerNib:nib forCellWithReuseIdentifier:CellIdentifier];
[imageDisplayer setBackgroundColor:myColor];
[self.view insertSubview:imageDisplayer belowSubview:navBar];
//[self.view addSubview:imageDisplayer];
}
#pragma mark - Setup
- (void)setupData
{
self.imageURLStrings = [NSMutableArray array];
// Save image to docs directory so we can get a nice URL
// Not sure how to get the URL from an asset catalog off the top of my head
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"greyBurger.png"];
UIImage *image = [UIImage imageNamed:#"greyBurger"];
NSData *data = UIImagePNGRepresentation(image);
[data writeToFile:path atomically:YES];
// Populate our imageURLStrings array with many paths
for (NSInteger i = 0; i < NumberOfImages; i++)
{
[self.imageURLStrings addObject:path];
//NSLog(#"Path %#", path);
}
}
- (void)setupCollectionView
{
UINib *nib = [UINib nibWithNibName:#"CollectionViewCell" bundle:nil];
[self.collectionView registerNib:nib forCellWithReuseIdentifier:CellIdentifier];
}
#pragma mark - UICollectionView Datasource
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
//return [self.imageURLStrings count];
return [titles count];
//return 2;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
CollectionViewCell *cell = (CollectionViewCell *)[collectionView dequeueReusableCellWithReuseIdentifier:CellIdentifier forIndexPath:indexPath];
//NSLog(#"CELL FOR COUNT:%lu", [titles count]);
NSString *title = [titles objectAtIndex:indexPath.row];
cell.backgroundColor = [UIColor whiteColor];
NSString *imageUrl = [thumbMediaUrl objectForKey:title];
NSURL *thumbUrl = [NSURL URLWithString:imageUrl];
UIImageView *imageView = [[UIImageView alloc] init];
NSData *imageData = [NSData dataWithContentsOfURL:thumbUrl];
imageView.image = [UIImage imageWithData:imageData];
cell.backgroundView = imageView;
cell.layer.shouldRasterize = YES;
cell.layer.rasterizationScale = [UIScreen mainScreen].scale;
//cell.frame = CGRectMake(0, 0, 100, 100);
//cell.imageURLString = [self.imageURLStrings objectAtIndex:indexPath.item];
return cell;
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
CGRect screenBound = [[UIScreen mainScreen] bounds];
CGSize screenSize = screenBound.size;
CGFloat screenWidth = screenSize.width;
NSString *title = [titles objectAtIndex:indexPath.row];
float width = [[thumbWidth objectForKey:title] floatValue];
float height = [[thumbHeight objectForKey:title] floatValue];
float imageWidth = (screenWidth / 2) - 3;
float scale = imageWidth / width;
float imageHeight = height * scale;
CGSize imageSize = CGSizeMake(imageWidth, imageHeight);
return imageSize;
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section {
return 2.0;
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section {
return 2.0;
}
// Layout: Set Edges
- (UIEdgeInsets)collectionView:
(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
// return UIEdgeInsetsMake(0,8,0,8); // top, left, bottom, right
return UIEdgeInsetsMake(0,0,0,0); // top, left, bottom, right
}
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
NSArray* attributesToReturn = [self layoutAttributesForElementsInRect:rect];
for (UICollectionViewLayoutAttributes* attributes in attributesToReturn)
{
if (nil == attributes.representedElementKind)
{
NSIndexPath* indexPath = attributes.indexPath;
attributes.frame = [self layoutAttributesForItemAtIndexPath:indexPath].frame;
}
}
return attributesToReturn;
}
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewLayoutAttributes* currentItemAttributes = [self layoutAttributesForItemAtIndexPath:indexPath];
if (indexPath.item < numColumns){
CGRect f = currentItemAttributes.frame;
f.origin.y = 0;
currentItemAttributes.frame = f;
return currentItemAttributes;
}
NSIndexPath* ipPrev = [NSIndexPath indexPathForItem:indexPath.item-numColumns inSection:indexPath.section];
CGRect fPrev = [self layoutAttributesForItemAtIndexPath:ipPrev].frame;
CGFloat YPointNew = fPrev.origin.y + fPrev.size.height + 10;
CGRect f = currentItemAttributes.frame;
f.origin.y = YPointNew;
currentItemAttributes.frame = f;
return currentItemAttributes;
}
I have changed my code based on suggestions of The first two answers, now i have to to get the images to add to a running view. and make each column have their own independent height so there is a 2px spacing at each edge, This is what i tried for reloading data
-(void)refreshView {
[self rwDataToPlist];
[self.collectionView reloadData];
[self setupCollectionView];
}

With starting iOS6 itself Apple Introduced for UICollectionView. You can Use UICollectionView with Pull to Bottom Refresh to Achieve your Goal. Its look like UITableView Pull to Bottom Refresh.
Here Are Some Reference for UIcollectionView:
Source Code
Beginning UICollectionView
UICollectionView with StoryBoard
Once You create UICollectionView then You need to Add PulltoBottom Refresh for your UICollectionView like following code:
-(void)viewWillAppear:(BOOL)animated
{
[self.collectionView.infiniteScrollingView setActivityIndicatorViewStyle:UIActivityIndicatorViewStyleWhite];
[self.collectionView addInfiniteScrollingWithActionHandler:^{
////(#"Infinitescroll");
#try {
int64_t delayInSeconds = 2.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
//[self.dataSource addObjectsFromArray:tmp];
[self.collectionView performBatchUpdates:^{
} completion:nil];
[self.collectionView.infiniteScrollingView stopAnimating];
});
}
#catch (NSException *exception) {
}
}];
[super viewWillAppear:animated];
}
For Below code you must Add some files:
SVPulltoReferesh Link

A few suggestions / questions:
Not knowing the constraints of your particular problem, it sounds like you're trying to display some semblance of a grid of images, and load the "next page" of images when a user scrolls beyond a certain point. It seems like a UITableView or UICollectionView would be a more appropriate mechanism to do what you're trying to do. Both of those classes will handle lazy loading of images, pagination via a properly configured datasource, automatic contentSize adjustments, and will be blazing fast without mainThread freezes. They're also based on the MVC design pattern and will likely clarify some of the design in the code above.
The reason the UI/scrolling freezes when you load more images is likely due to reading both userDefaults and the image data itself from disk. Disk operations can be expensive, especially many at a time. If you must load the metadata and image files this way, consider doing this processing on a background thread via GCD's dispatch_async.
The reason the second set of images is not appearing is likely due to image frame or scrollView contentSize miscalculation. Consider debugging by adding a series of colored UIViews to the scrollView instead of UIImageViews, and consider hard coding the contentSize.height to something much larger than you need. Also, have you NSLogged the image frames and contentSize to make sure they match up?
Edit:
Here's a link to a quick sample project using a UICollectionView and a background thread for reading UIImage data from disk (which isn't really necessary anymore due to using UICollectionView):
https://github.com/alfiehanssen/SOImageGrid
Let me know if you have questions, hopefully I'm not totally off the mark in terms of your goals.

I used a UICollectionView as suggested in the first two answers and added CHTCollectionViewWaterfallLayout to it to allow the image spacing i wanted
My Code:
#pragma mark - Collection View
#pragma mark - Display Collection
-(void)displayCollection {
UIColor *myColor = [UIColor colorWithRed:(245.0 / 255.0) green:(245.0 / 255.0) blue:(245.0 / 255.0) alpha: 1];
CGRect screenBound = [[UIScreen mainScreen] bounds];
CGSize screenSize = screenBound.size;
CGFloat screenWidth = screenSize.width;
CGFloat screenHeight = screenSize.height;
self.view = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
CGRect locOfScree = CGRectMake(0, 44, screenWidth, screenHeight - 44);
CHTCollectionViewWaterfallLayout *layout = [[CHTCollectionViewWaterfallLayout alloc] init];
layout.sectionInset = UIEdgeInsetsMake(2, 2, 2, 2);
layout.headerHeight = 0;
layout.footerHeight = 0;
layout.minimumColumnSpacing = 2;
layout.minimumInteritemSpacing = 2;
//UICollectionViewFlowLayout *layout=[[UICollectionViewFlowLayout alloc] init];
imageDisplayer = [[UICollectionView alloc] initWithFrame:locOfScree collectionViewLayout:layout];
imageDisplayer.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
[imageDisplayer setDataSource:self];
[imageDisplayer setDelegate:self];
UINib *nib = [UINib nibWithNibName:#"CollectionViewCell" bundle:nil];
[imageDisplayer registerNib:nib forCellWithReuseIdentifier:CellIdentifier];
[imageDisplayer setBackgroundColor:myColor];
[self.view insertSubview:imageDisplayer belowSubview:navBar];
//[self.view addSubview:imageDisplayer];
imageDisplayer = [[UICollectionView alloc] initWithFrame:self.view.bounds collectionViewLayout:layout];
imageDisplayer.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
imageDisplayer.dataSource = self;
imageDisplayer.delegate = self;
imageDisplayer.backgroundColor = [UIColor whiteColor];
[imageDisplayer registerClass:[CHTCollectionViewWaterfallCell class]
forCellWithReuseIdentifier:CellIdentifier];
}
#pragma mark - Setup
- (void)setupCollectionView
{
UINib *nib = [UINib nibWithNibName:#"CollectionViewCell" bundle:nil];
[self.collectionView registerNib:nib forCellWithReuseIdentifier:CellIdentifier];
}
#pragma mark - UICollectionView Datasource
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
//return [self.imageURLStrings count];
return [titles count];
//return 2;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
/*
CollectionViewCell *cell = (CollectionViewCell *)[collectionView dequeueReusableCellWithReuseIdentifier:CellIdentifier forIndexPath:indexPath];
*/
CHTCollectionViewWaterfallCell *cell =
(CHTCollectionViewWaterfallCell *)[collectionView dequeueReusableCellWithReuseIdentifier:CellIdentifier
forIndexPath:indexPath];
NSString *title = [titles objectAtIndex:indexPath.row];
cell.backgroundColor = [UIColor whiteColor];
NSString *imageUrl = [thumbMediaUrl objectForKey:title];
NSURL *thumbUrl = [NSURL URLWithString:imageUrl];
UIImageView *imageView = [[UIImageView alloc] init];
NSData *imageData = [NSData dataWithContentsOfURL:thumbUrl];
imageView.image = [UIImage imageWithData:imageData];
cell.backgroundView = imageView;
cell.layer.shouldRasterize = YES;
cell.layer.rasterizationScale = [UIScreen mainScreen].scale;
return cell;
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
CGRect screenBound = [[UIScreen mainScreen] bounds];
CGSize screenSize = screenBound.size;
CGFloat screenWidth = screenSize.width;
NSString *title = [titles objectAtIndex:indexPath.row];
float width = [[thumbWidth objectForKey:title] floatValue];
float height = [[thumbHeight objectForKey:title] floatValue];
float imageWidth = (screenWidth / 2) - 3;
float scale = imageWidth / width;
float imageHeight = height * scale;
CGSize imageSize = CGSizeMake(imageWidth, imageHeight);
return imageSize;
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section {
return 2.0;
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section {
return 2.0;
}
// Layout: Set Edges
- (UIEdgeInsets)collectionView:
(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
// return UIEdgeInsetsMake(0,8,0,8); // top, left, bottom, right
return UIEdgeInsetsMake(0,0,0,0); // top, left, bottom, right
}
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
NSArray* attributesToReturn = [self layoutAttributesForElementsInRect:rect];
for (UICollectionViewLayoutAttributes* attributes in attributesToReturn)
{
if (nil == attributes.representedElementKind)
{
NSIndexPath* indexPath = attributes.indexPath;
attributes.frame = [self layoutAttributesForItemAtIndexPath:indexPath].frame;
}
}
return attributesToReturn;
}
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewLayoutAttributes* currentItemAttributes = [self layoutAttributesForItemAtIndexPath:indexPath];
if (indexPath.item < numColumns){
CGRect f = currentItemAttributes.frame;
f.origin.y = 0;
currentItemAttributes.frame = f;
return currentItemAttributes;
}
NSIndexPath* ipPrev = [NSIndexPath indexPathForItem:indexPath.item-numColumns inSection:indexPath.section];
CGRect fPrev = [self layoutAttributesForItemAtIndexPath:ipPrev].frame;
CGFloat YPointNew = fPrev.origin.y + fPrev.size.height + 10;
CGRect f = currentItemAttributes.frame;
f.origin.y = YPointNew;
currentItemAttributes.frame = f;
return currentItemAttributes;
}

Related

viewForSupplementaryElementOfKind not being called on custom UICollectionViewLayout

I created a custom UICollectionViewLayout and I've put it in my Collection View Controller in the storyboard. I didn't get that much problems on displaying the items/cells. My problem is that the viewForSupplementaryElementOfKind is not being called. I can't to seem to pinpoint on why is that. I tried to go back to the default layout and it does call it then but I need my custom UICollectionViewLayout. I've left NSLogs to check and viewForSupplementaryElementOfKind is not being called.
Here is my MyCollectionViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
viewArray = [NSMutableArray array];
//setup the delegate for vertical flow layout
[(VerticalFlowLayout*)self.collectionViewLayout setDelegate:self];
//register the headers
[self.collectionView registerNib:[ButtonHeaderCollectionReusableView nib] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:[ButtonHeaderCollectionReusableView reusableID]];
//set the insets
[self.collectionView setContentInset:UIEdgeInsetsMake(23, 5, 10, 5)];
}
#pragma mark - CollectionView DataSource
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return [self.cardsArray count];
}
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
NSLog(#"Number of Sections");
return 1;
}
- (UICollectionViewCell*)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#"Making Card");
CardCell *card = [collectionView dequeueReusableCellWithReuseIdentifier:#"CardCell" forIndexPath:indexPath];
// UILabel *cardLabel = [card viewWithTag:101];
// [cardLabel setText:[textArray objectAtIndex:[indexPath row]]];
return card;
}
- (UICollectionReusableView*)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath {
NSLog(#"Making Header");
UICollectionReusableView *reusableView = nil; /*[[UICollectionReusableView alloc] initWithFrame:CGRectMake(0, 0, 100, 75)];*/
// [reusableView setBackgroundColor:[UIColor blackColor]];
if (kind == UICollectionElementKindSectionHeader) {
ButtonHeaderCollectionReusableView *headerview = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:[ButtonHeaderCollectionReusableView reusableID] forIndexPath:indexPath];
return headerview;
}
// if (kind == UICollectionElementKindSectionFooter) {
// UICollectionReusableView *footerview = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionFooter withReuseIdentifier:#"FooterView" forIndexPath:indexPath];
// }
return reusableView;
}
- (CGSize)collectionView:collectionView layout:(nonnull UICollectionViewLayout *)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section {
return CGSizeMake(180.0f, 72.0f);
}
Now here is my MyFlowLayout.m
- (id)initWithCoder:(NSCoder *)aDecoder {
NSLog(#"Vertical Flow Layout init with coder");
if(self = [super initWithCoder:aDecoder]) {
contentHeight = 0;
cachedAttributes = [NSMutableArray array];
}
return self;
}
- (void)prepareLayout {
NSLog(#"Preparing Layout");
// [super prepareLayout];
contentWidth = CGRectGetWidth(self.collectionView.bounds) - (self.collectionView.contentInset.left + self.collectionView.contentInset.right);
if([cachedAttributes count] == 0) {
//compute for column width
CGFloat columnWidth = contentWidth / NUMBER_OF_COLUMNS;
NSMutableArray *xOffsets = [NSMutableArray array];
for(int i = 0; i < NUMBER_OF_COLUMNS; i++) {
[xOffsets addObject:[NSNumber numberWithFloat:(i * columnWidth)]];
}
//compute for height
NSMutableArray *yOffsets = [NSMutableArray array];
for(int i = 0; i < NUMBER_OF_COLUMNS; i++) {
[yOffsets addObject:[NSNumber numberWithFloat:75]];
}
int column = 0;
//loop through all the sections and items in the collectionview
for(int i = 0; i < self.collectionView.numberOfSections; i++) {
for(int j = 0; j < [self.collectionView numberOfItemsInSection:i]; j++) {
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:j inSection:i];
//time to do some frame calculation
///let's start with the width
CGFloat width = columnWidth - CELL_PADDING * 2;
///then the height
CGFloat viewHeight = [self.delegate getViewHeightWithCollectionView:self.collectionView indexPath:indexPath withWidth:width];
CGFloat height = CELL_PADDING + viewHeight + /*textHeight +*/ CELL_PADDING;
CGFloat xOffset = [[xOffsets objectAtIndex:column] floatValue];
CGFloat yOffset = [[yOffsets objectAtIndex:column] floatValue];
CGRect frame = CGRectMake(xOffset, yOffset, columnWidth, height);
CGRect insetFrame = CGRectInset(frame, CELL_PADDING, CELL_PADDING);
//now that computation is done we shall make the attributes
UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
[attributes setFrame:insetFrame];
[cachedAttributes addObject:attributes];
//time to increment the height and the column
contentHeight = MAX(contentHeight, CGRectGetMaxY(frame));
NSNumber *yOffSetColumn = [yOffsets objectAtIndex:column];
yOffSetColumn = [NSNumber numberWithFloat:([yOffSetColumn floatValue] + height)];
[yOffsets replaceObjectAtIndex:column withObject:yOffSetColumn];
NSLog(#"Content Height: %f yOffSetColumn: %# == %#", contentHeight, yOffSetColumn, [yOffsets objectAtIndex:column]);
column = column >= (NUMBER_OF_COLUMNS - 1) ? 0 : ++column;
}
}
}
}
- (CGSize)collectionViewContentSize {
// NSLog(#"Collection View Content Size");
return CGSizeMake(contentWidth, contentHeight + 75);
}
// called after preparelayout to determine which items are visible in the given rect
- (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect {
NSMutableArray<UICollectionViewLayoutAttributes *> *layoutAttributes = [NSMutableArray array];
NSInteger sectionsCount = [self.collectionView.dataSource numberOfSectionsInCollectionView:self.collectionView];
NSLog(#"Sections count: %ld", (long)sectionsCount);
for(int i = 0; i < sectionsCount; i++) {
//for header
UICollectionViewLayoutAttributes *headerAttributes = [self layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionHeader atIndexPath:[NSIndexPath indexPathForItem:0 inSection:i]];
// if(CGRectIntersectsRect(headerAttributes.frame, rect)) {
// NSLog(#"Adding Section Attribute");
[layoutAttributes addObject:headerAttributes];
// }
for (UICollectionViewLayoutAttributes *attributes in cachedAttributes) {
if(CGRectIntersectsRect(attributes.frame, rect)) {
[layoutAttributes addObject:attributes];
}
}
// NSInteger itemsCount = [self.collectionView numberOfItemsInSection:i];
// for(int j = 0; j < itemsCount; j++) {
// UICollectionViewLayoutAttributes *attributes = [self layoutAttributesForItemAtIndexPath:[NSIndexPath indexPathForItem:j inSection:i]];
// if(CGRectIntersectsRect(attributes.frame, rect)) {
// [layoutAttributes addObject:attributes];
// }
// }
}
return layoutAttributes;
}
//- (UICollectionViewLayoutAttributes*)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath {
// NSLog(#"Layout Attributes For Item: %ld %ld", [indexPath row], [indexPath section]);
//
// UICollectionViewLayoutAttributes *attributes = [cachedAttributes objectAtIndex:[indexPath row]];
// return attributes;
//}
- (UICollectionViewLayoutAttributes *)layoutAttributesForSupplementaryViewOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath {
NSLog(#"Layout Attributes For Header: %# %ld %ld", elementKind, [indexPath row], [indexPath section]);
UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
[attributes setFrame:CGRectMake(0, 0, contentWidth /*320*/, 75.0f)];
return attributes;
}
As you can see in MyFlowLayout, there are things I've tried but still it didn't call viewForSupplementaryElementOfKind. I tried implementing layoutAttributesForItemAtIndexPath since I have layoutAttributesForSupplementaryViewOfKind. I tried also using fixed numbers like the 75 and 320 that you see just to check if the header would be generated. The delegate that you see, it's just for getting a height of a view.
Since I've given the header enough space to be seen and left NSLogs all over and yet (UICollectionReusableView*)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath is not being called.
Here are some that I've looked and tried: stackoverflow but as you can see from the commented code that I've included. It still didn't work.
Thanks for the help.
I also had a problem with this and my solution was to simply add attributes for section in prepareLayout
UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionHeader withIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]];
attributes.frame = CGRectMake(0, 0, self.collectionView.frame.size.width, 100);
[cachedAttributes addObject:attributes];
Add the default size of header section:
collectionViewLayout.headerReferenceSize = CGSize(width, height)
The default size values are (0, 0). Thats why header is not displaying.
OR
There is also another way for it, implement the delegate method for UICollectionView:
collectionView(_:layout:referenceSizeForFooterInSection:)

Create Multi UICollectionView in a ViewController

Title is my problem.
I had created UICollectionView in for loop. So, it's created some UICollectionView
My code:
for (int i = 0; i < getAllCategory.count; i ++) {
CGRect frame;
frame.origin.x = self.scroll.frame.size.width * i;
frame.origin.y = 0;
frame.size = self.scroll.frame.size;
UICollectionViewFlowLayout *layout=[[UICollectionViewFlowLayout alloc] init];
collectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(screenWidth*i,5,screenWidth ,self.scroll.frame.size.height-5) collectionViewLayout:layout];
[collectionView setDataSource:self];
[collectionView setDelegate:self];
[collectionView setPagingEnabled:YES];
collectionView.showsHorizontalScrollIndicator = NO;
collectionView.showsVerticalScrollIndicator = NO;
[collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:#"cellIdentifier"];
[collectionView setBackgroundColor:[UIColor purpleColor]];
[self.scroll addSubview:collectionView];
}
So, When I scroll to new UICollectionView to show new image, it's not show new image. Because, it's reload data for last UICollectionView.
My code when show new image.
- (void)scrollViewDidScroll:(UIScrollView *)sender {
if (!pageControlBeingUsed) {
[getAllEmoji removeAllObjects];
// Switch the indicator when more than 50% of the previous/next page is visible
CGFloat pageWidth = self.scroll.frame.size.width;
int page = floor((self.scroll.contentOffset.x - pageWidth / 2) / pageWidth) + 1;
self.pageControl.currentPage = page;
//Change Emoji when scroll
NSString *str = [getAllCategory objectAtIndex:page];
NSArray *arr = [Emoji MR_findByAttribute:#"category" withValue:str];
if (arr.count > 0) {
for (int i = 0; i < arr.count; i++) {
Emoji *emoji = [arr objectAtIndex:i];
[getAllEmoji addObject:emoji.name_emoji];
}
[collectionView reloadData];
}
}
}
So, it's only show old image for all UICollectionView, it's only change image for last UICollectionView
How to I can resolve this problem.
Here is link to you see some images my problem
http://imgur.com/a/nIMic
Please help me!
************************** I had resolved my problem *******************
Add code
#property (strong, nonatomic) NSMutableArray *collectionArray;
self.collectionArray = [[NSMutableArray alloc]init];
[self.collectionArray addObject:collectionView];
[self.collectionArray[page] reloadData];
Your code just handles a collectionView (the last collection).
You should create a property to hold these collectionView: NSMutableArray * arrCollectionView
for (int i = 0; i < getAllCategory.count; i ++) {
CGRect frame;
frame.origin.x = self.scroll.frame.size.width * i;
frame.origin.y = 0;
frame.size = self.scroll.frame.size;
UICollectionViewFlowLayout *layout=[[UICollectionViewFlowLayout alloc] init];
UICollectionView * collectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(screenWidth*i,5,screenWidth ,self.scroll.frame.size.height-5) collectionViewLayout:layout];
[collectionView setDataSource:self];
[collectionView setDelegate:self];
[collectionView setPagingEnabled:YES];
collectionView.showsHorizontalScrollIndicator = NO;
collectionView.showsVerticalScrollIndicator = NO;
[collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:#"cellIdentifier"];
[collectionView setBackgroundColor:[UIColor purpleColor]];
[self.scroll addSubview:collectionView];
[arrCollectionView addObject: collectionView];
}
Then in scrollViewDidScroll
- (void)scrollViewDidScroll:(UIScrollView *)sender {
if (!pageControlBeingUsed) {
[getAllEmoji removeAllObjects];
// Switch the indicator when more than 50% of the previous/next page is visible
CGFloat pageWidth = self.scroll.frame.size.width;
int page = floor((self.scroll.contentOffset.x - pageWidth / 2) / pageWidth) + 1;
self.pageControl.currentPage = page;
//Change Emoji when scroll
NSString *str = [getAllCategory objectAtIndex:page];
NSArray *arr = [Emoji MR_findByAttribute:#"category" withValue:str];
if (arr.count > 0) {
for (int i = 0; i < arr.count; i++) {
Emoji *emoji = [arr objectAtIndex:i];
[getAllEmoji addObject:emoji.name_emoji];
}
//[collectionView reloadData];
for (UICollectionView * collectionView in arrCollectionView) {
if (collectionView == sender) {
[collectionView reloadData];
break;
}
}
}
}
}
Please thinking your design model, you can separate the UICollectionView in different Class, every pointer to object by self, create different array and datasource for load.

Image not loading properly in landscape mode in UIScrollView with Page Control

I need to be able to load images properly in both the landscape and portrait mode and for all devices.
Also I need a proper memory management while loading the images. right now my code loads all the images at once but in future I will add more images so need an optimized memory solution.
- (void)viewDidLoad {
[super viewDidLoad];
self.automaticallyAdjustsScrollViewInsets = NO;
self.navigationController.navigationBarHidden = YES;
_photoArray = [NSArray arrayWithObjects:#"image1.jpg",#"image2.jpg",#"image3.jpg",#"image4.jpg",#"image5.jpg",#"image6.jpg",#"image7.jpg",#"image8.jpg",#"image9.jpg", nil];
self.pageControl.numberOfPages = _photoArray.count;
CGSize screen = [[UIScreen mainScreen] bounds].size;
for(int i = 0; i < _photoArray.count; i++)
{
self.subScrollView = [[UIScrollView alloc] init];
self.subScrollView.frame = CGRectMake((i * screen.width), 0, screen.width, screen.height);
[self.subScrollView setMinimumZoomScale:1];
[self.subScrollView setZoomScale:1];
[self.subScrollView setMaximumZoomScale:3];
self.subScrollView.delegate = self;
UIImageView *imgView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:_photoArray[i]]];
imgView.frame = self.subScrollView.bounds;
imgView.contentMode = UIViewContentModeScaleAspectFit;
imgView.clipsToBounds = YES;
imgView.tag = i;
[self.subScrollView addSubview:imgView];
[_scrView addSubview:self.subScrollView];
if(i == _photoArray.count-1)
_scrView.contentSize = CGSizeMake(self.subScrollView.frame.origin.x + self.subScrollView.frame.size.width, screen.height);
}
}
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
return [scrollView viewWithTag:self.pageControl.currentPage];
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
//page control
CGFloat pageWidth = self.scrView.frame.size.width;
self.pageControl.currentPage = (self.scrView.contentOffset.x +pageWidth/2)/pageWidth;
}
I think that the best option to optimize the memory is use a UICollectionView instead UIScrollView. Also you can use UIPageControl with UICollectionView.
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
return 1;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return self.imagesArray.count;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
UICollectionViewCell *cell == [collectionView dequeueReusableCellWithReuseIdentifier:#"cell" forIndexPath:indexPath];
UIImageView *image = [[UIImageView alloc] initWithImage:[UIImage imageNamed:[NSString stringWithFormat:#"image%d.jpg",indexPath.row]]];
[cell.addSubView:image];
return cell;
}

UIcollection view support cover flow

Hi friends is it possible to add a cover flow effect in uicollection view in horizontal layout.if possible means kindly tell me how to implement the effect.
Yes it is possible, You need to Implement your custom UICollectionViewFlowLayout.
Make a custom class which inherits UICollectionViewFlowLayout
- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds {
return YES; }
- (UICollectionViewScrollDirection)scrollDirection {
return UICollectionViewScrollDirectionVertical; }
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {
UICollectionView *collectionView = [self collectionView];
UIEdgeInsets insets = [collectionView contentInset];
CGPoint offset = [collectionView contentOffset];
CGFloat minY = -insets.top;
NSArray *attributes = [super layoutAttributesForElementsInRect:rect];
// minY is Point where we implement this cover flow.
if (offset.y < minY) {
// Figure out how much we've pulled down
CGFloat deltaY = fabsf(offset.y - minY);
for (UICollectionViewLayoutAttributes *attrs in attributes) {
// Locate the header attributes
NSString *kind = [attrs representedElementKind];
if (kind == UICollectionElementKindSectionHeader) {
// This is header's height and y based on how much the user has scrolled down.
CGSize headerSize = [self headerReferenceSize];
CGRect headerRect = [attrs frame];
headerRect.size.height = MAX(minY, headerSize.height + deltaY);
headerRect.origin.y = headerRect.origin.y - deltaY;
[attrs setFrame:headerRect];
break;
}
}
}
return attributes; }
Now in your class where you allocate UICollectionView
CustomCoverFlowHeaderCollectionViewLayout *flow; flow = [[CustomCoverFlowHeaderCollectionViewLayout alloc] init]; [stretchyLayout setHeaderReferenceSize:CGSizeMake(320.0, 160.0)]; // Set our custom layout [collectionView setCollectionViewLayout: flow]; [collectionView setAlwaysBounceVertical:YES]; [collectionView registerClass:[UICollectionReusableView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader
withReuseIdentifier:#"myCoverCollectionView"];
You are almost done
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView
viewForSupplementaryElementOfKind:(NSString *)kind
atIndexPath:(NSIndexPath *)indexPath {
if (!header) {
header = [collectionView dequeueReusableSupplementaryViewOfKind:kind
withReuseIdentifier:#"myCoverCollectionView" forIndexPath:indexPath];
CGRect bounds;
bounds = [header bounds];
UIImageView *imageView;
imageView = [[UIImageView alloc] initWithFrame:bounds];
[imageView setImage:[UIImage imageNamed:#"background"]];
[imageView setContentMode:UIViewContentModeScaleAspectFill];
[imageView setClipsToBounds:YES];
[imageView setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
[header addSubview:imageView];
}
return header; }
Here is a good project based on UICollectionView for you.

dequeueReusableCellWithReuseIdentifier gone wrong after scroll on collectionview

I've got this problem with a UICollectionView inside a UICollectionViewCell:
The last UICollectionViewCell doesn't get filled with 13 - 18, but instead, the first one get's copied.
I know it has something to do with "dequeueReusableCellWithReuseIdentifier" but if I don't do the check on the tag below, my entire collection gets messed up.
I've been struggling with this issue and Googling around for about a day now, but I can't find how to fix this.
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
NSString *cellID=#"pageCell";
UICollectionViewCell *cell=[collectionView dequeueReusableCellWithReuseIdentifier:cellID forIndexPath:indexPath];
int no = indexPath.item;
if(collectionView == _pageCollectionView)
{
//Collection pages
cell.tag=no+1;
UICollectionViewFlowLayout *layoutMods=[[UICollectionViewFlowLayout alloc] init];
[layoutMods setSectionInset:UIEdgeInsetsMake(0, 0, 0, 0)];
[layoutMods setMinimumInteritemSpacing:0];
[layoutMods setMinimumLineSpacing:0];
[layoutMods setItemSize:CGSizeMake(125, 125)];
_modsCollectionView=[[UICollectionView alloc] initWithFrame:CGRectMake(0,0, _pageCollectionView.frame.size.width, _pageCollectionView.frame.size.height) collectionViewLayout:layoutMods];
[_modsCollectionView setDataSource:self];
[_modsCollectionView setDelegate:self];
_modsCollectionView.pagingEnabled = YES;
[_modsCollectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:#"pageCell"];
NSMutableArray *randColor = [[NSMutableArray alloc] init];
for(int i=0;i<3;i++)
{
int lowerBound = 0;
int upperBound = 255;
NSNumber *rndValue = [NSNumber numberWithFloat:(lowerBound + arc4random() % (upperBound - lowerBound) )/255.0];
[randColor insertObject:rndValue atIndex:i];
}
float r = [[randColor objectAtIndex:0] floatValue];
float g = [[randColor objectAtIndex:1] floatValue];
float b = [[randColor objectAtIndex:2] floatValue];
_modsCollectionView.backgroundColor = [UIColor colorWithRed:r green:g blue:b alpha:1];
[cell addSubview:_modsCollectionView];
}
else
{
if(cell.tag == 0)
{
cell.tag = 2;
NSMutableDictionary *mod=[modules objectAtIndex:modulePointer];
cell.backgroundColor=[mod objectForKey:#"color"];
NSString *slug = [mod objectForKey:#"slug"];
NSString *imgName=[NSString stringWithFormat:slug,#".png"];
UIImageView *customBackground = [[UIImageView alloc] initWithImage:[UIImage imageNamed:imgName]];
customBackground.frame = CGRectMake(0,0, 125, 125);
[cell addSubview:customBackground];
customBackground.contentMode = UIViewContentModeScaleAspectFit;
customBackground.clipsToBounds = YES;
modulePointer++;
}
}
return cell;
}
What am I doing wrong?
Got it! I had to work some magic using view tags inside - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath.
In the if(collectionView == _pageCollectionView) i put:
for(id subview in [cell subviews])
{
[subview removeFromSuperview];
}
cell.tag=itemsPerScreen*no;
And then in the following else:
int thisIndex=[collectionView superview].tag+no;
NSMutableDictionary *mod=[modules objectAtIndex:thisIndex];
You need to create your own custom UICollectionViewCell to prevent this from happening.

Resources