I am trying to make an app with CollectionView, but I'm facing a problem. As you can see from my code, I received the callback in both numberofSectionsINCollectionView and numberOfItemsInsection, but cannot receive the callback in cellForItemAtIndexPath, which makes the cell not show up inside CollectionView. However, with another computer with the same Xcode version and connected to the same iPhone (6 Plus), I can receive the callback in cellForItemAtIndexPath.
I don't know why. Could you please tell me how to fix the problem? I think it's attributed to the setting in Xcode, but I'm not sure.
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
if (self.useSection) {
return self.dataSource.count;
}
return 1;}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
if (self.useSection)
return [[self.dataSource objectAtIndex:section] count];
return self.dataSource.count; }
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell = [self.collectionView dequeueReusableCellWithReuseIdentifier:[self reuseIdentifierForIndexPath:indexPath] forIndexPath:indexPath];
return cell;
}
I double-checked if delegate is set like
self.collectionView.delegate = self;
self.collectionView.dataSource = self;
cellForItemAtIndexPath won't be called if your cell size is (0,0) or count is 0 maybe you can try add this code :
- (CGSize)collectionView:(UICollectionView *)collectionView layout:
(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:
(NSIndexPath *)indexPath{ return CGSizeMake(100,100);}
Related
I've a strange behavior with UICollectionView.
In Figure 1 is shown the correct behavior when the user scroll up the collection: the items goes under header view.
[FIGURE 1]
When I reload Items after a search, some items goes over header during scroll.
I've no idea about the cause...
Any ideas or suggestions?
Thanks.
EDIT
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section
{
return CGSizeMake(CGRectGetWidth([UIScreen mainScreen].bounds), CGRectGetWidth([UIScreen mainScreen].bounds) * 0.612f);
}
What worked for me is to call reloadData() instead of trying to reload with animation (reloadSections()).
In my case, I had a show/hide button to toggle the number of rows in section between item count and 0 (expand the content of the section).
When I replaced
collectionView?.reloadSections([section])
with
collectionView?.reloadData()
I no longer had the issue.
My working code for UICollectionView along with HeaderView inside UIViewController:
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
return 1;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return 20;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"cell" forIndexPath:indexPath];
cell.backgroundColor = [UIColor blueColor];
return cell;
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
return CGSizeMake(100, 100);
}
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
{
UICollectionReusableView *view = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:#"header" forIndexPath:indexPath];
return view;
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section
{
return CGSizeMake(self.view.frame.size.width, 100);
}
Storyboard:
Output:
Please check this. Hope this will help you in some other way.
You can try to set sectionHeadersPinToVisibleBounds = true property on your UICollectionViewFlowLayout. Because every UICollectionView has own layout.
Apple doc
A Boolean value indicating whether headers pin to the top of the collection view bounds during scrolling.
Maybe it will help. Add this code into viewDidLoad.
(self.yourCollectionView.collectionViewLayout as! UICollectionViewFlowLayout).sectionHeadersPinToVisibleBounds = true
After trying many solutions in my case that works,
collectionView.clipsToBounds = true
I would like to have a UICollectionView that, in the first row there is a cell with all the row's width, and the second row has 3 cells.
I have researched the documentation but I'm not able to do it. Something like this:
Thanks in advance
Make 2 Cell prototypes in collection view in your storyboard, and set them reuse identifiers
In your ViewController's .m file implement this functions
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
return 1;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return 6;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell;
if (/*condition for small cell*/)// e.g. indexPath.row % 3 != 0
cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"smallCell" forIndexPath:indexPath];
else
cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"bigCell" forIndexPath:indexPath];
return cell;
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
if (/*condition for small cell*/) // e.g. indexPath.row % 3 != 0
return CGSizeMake(65, 50);
return CGSizeMake(318, 50);
}
After doing this you will have something like this:
When calling -reloadData several times, -collectionView:didSelectItemAtIndexPath: or -collectionView:didDeselectItemAtIndexPath: not called.
(When calling once or twice, the method is called correctly.)
Running -reloadData is not taking a lot of time. Memory or CPU usage is also not busy.
Why are there times when -collectionView:didSelectItemAtIndexPath: is not called?
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
CustomCollectionCell* cell = [collectionView dequeueReusableCellWithReuseIdentifier:kCellIdentifier forIndexPath:indexPath];
return cell;
}
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"select %d", indexPath.item);
[collectionView reloadData];
}
- (void)collectionView:(UICollectionView *)collectionView didDeselectItemAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"deselect %d", indexPath.item);
[collectionView reloadData];
}
CustomCollectionCell.m
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
//
}
return self;
}
Also you have to add numberOfItemsInSection function to your code. It returns the number of items in the specified section. Without this you can't call collectionView:didSelectItemAtIndexPath function.
Also call your [collectionView reloadData]; in your viewDidLoad or viewDidAppear.
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return [self.yourArray count];
}
I have moved collectionView to my ViewController, created IBOutlet, established connection with dataSource and delegate, added protocols: UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout, and also added methods:
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection: (NSInteger)section
{
return 5;
}
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
return 1;
}
- (AdImageCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
AdImageCell *cell = (AdImageCell *)[collectionView dequeueReusableCellWithReuseIdentifier:#"AdImageCellIdentifier" forIndexPath:indexPath];
cell.imageView1.image = [UIImage imageNamed:#"3.jpg"];
return cell;
}
I also created custom cell and add this to viewDidLoad:
[self.collectionView registerNib:[UINib nibWithNibName:#"AdImageCell" bundle:[NSBundle mainBundle]] forCellWithReuseIdentifier:#"AdImageCellIdentifier"];
But my problem here is that numberOfItemsInSection and numberOfSectionsInCollectionView is only called, but not cellForItemAtIndexPath. Why?
Sometimes it will work if you remove the collectionView registerClass:forCellWithReuseIdentifier from the viewDidLoad method.
collectionView:cellForItemAtIndexPath: never gets called
Hope it will help you..
I would like to have a UICollectionView that, in the first row there is a cell with all the row's width, and the second row has 3 cells.
I have researched the documentation but I'm not able to do it. Something like this:
Thanks in advance
Make 2 Cell prototypes in collection view in your storyboard, and set them reuse identifiers
In your ViewController's .m file implement this functions
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
return 1;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return 6;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell;
if (/*condition for small cell*/)// e.g. indexPath.row % 3 != 0
cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"smallCell" forIndexPath:indexPath];
else
cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"bigCell" forIndexPath:indexPath];
return cell;
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
if (/*condition for small cell*/) // e.g. indexPath.row % 3 != 0
return CGSizeMake(65, 50);
return CGSizeMake(318, 50);
}
After doing this you will have something like this: