Hi i have created one UIViewController in that i added one UICollectionView with CustomCell. Then, i created a uicollectionviewcell class for cell. Finally set the delegate and datasource in storybord itself. But it showing empty page. like in below image
CODE:
- (void)viewDidLoad
{
[super viewDidLoad];
self.collectionview = _collectionview;
self.collectionview.dataSource = self;
self.collectionview.delegate = self;
speakersImages=[[NSMutableArray alloc]init];
// Do any additional setup after loading the view, typically from a nib.
imageLabels=[[NSMutableArray alloc]initWithObjects:#"RB Forum 2013",#"Agenda",#"Speakers",#"Contact",#"Map",#"Websites",#"#Responsible Biz",#"Partners",#"Sustainability",nil];
imagePaths=[[NSMutableArray alloc]initWithObjects:[UIImage imageNamed:#"RBform.png"],[UIImage imageNamed:#"agenda.png"],[UIImage imageNamed:#"speakers.png"],[UIImage imageNamed:#"contact.png"],[UIImage imageNamed:#"map.png"],[UIImage imageNamed:#"website.png"],[UIImage imageNamed:#"twitter.png"],[UIImage imageNamed:#"partners.png"],[UIImage imageNamed:#"sustainability.png"], nil];
[self.collectionview registerClass:[NewCell class] forCellWithReuseIdentifier:#"Cell"];
}
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
return 1;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView
numberOfItemsInSection:(NSInteger)section
{
return [imageLabels count];
}
//THE BELOW DELEGATE METHOD DOES NOT GET CALLED!
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
// we're going to use a custom UICollectionViewCell, which will hold an image and its label
//
static NSString *CellIdentifier = #"Cell";
NewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:CellIdentifier forIndexPath:indexPath];
// make the cell's title the actual NSIndexPath value
cell.labels.text = [NSString stringWithFormat:#"%#",[imageLabels objectAtIndex:indexPath.row]];
// load the image for this cell
NSLog(#"%#",imageLabels);
//NSString *imageToLoad = [NSString stringWithFormat:#"%d.JPG", indexPath.row];
// cell.image.image = [UIImage imageNamed:imageToLoad];
cell.images.image = [imagePaths objectAtIndex:indexPath.row];
return cell;
}
Solution is remove
[self.collectionview registerClass:[NewCell class] forCellWithReuseIdentifier:#"Cell"];
in storybord we dont need this
Code is ok but order is different.Assigning datasource and delegates before array is populated makes the number of cell returned to 0 ,since array is not yet populated
Try like this
speakersImages=[[NSMutableArray alloc]init];
// Do any additional setup after loading the view, typically from a nib.
imageLabels=[[NSMutableArray alloc]initWithObjects:#"RB Forum 2013",#"Agenda",#"Speakers",#"Contact",#"Map",#"Websites",#"#Responsible Biz",#"Partners",#"Sustainability",nil];
imagePaths=[[NSMutableArray alloc]initWithObjects:[UIImage imageNamed:#"RBform.png"],[UIImage imageNamed:#"agenda.png"],[UIImage imageNamed:#"speakers.png"],[UIImage imageNamed:#"contact.png"],[UIImage imageNamed:#"map.png"],[UIImage imageNamed:#"website.png"],[UIImage imageNamed:#"twitter.png"],[UIImage imageNamed:#"partners.png"],[UIImage imageNamed:#"sustainability.png"], nil];
[self.collectionview registerClass:[NewCell class] forCellWithReuseIdentifier:#"Cell"];
[self.collectionview reloadData];
this line is not needed
self.collectionview = _collectionview;
self.collectionview.dataSource = self;
self.collectionview.delegate = self;
also make sure your collection view is connected via outlet
make sure the <UICollectioniewDatasource,UICollectionviewDelegate> is there in the class header
In Your storyboard give your imageview a tag e.g. 1, and your label another tag e.g. 2
Give your cell reuse identifier that you have already gave eg. "Cell"
Now in your storyboard right click on collection view and create datasource and delegate to your viewController or file owner. alternatively you can use <UICollectionViewDataSource,UICollectionViewDelegate> in your viewController and set the delegate and datasource to self.
Now in your viewDidLoad
-(void) viewDidLoad {
self.collectionview.dataSource = self;
self.collectionview.delegate = self;
speakersImages=[[NSMutableArray alloc]init];
// Do any additional setup after loading the view, typically from a nib.
imageLabels=[[NSMutableArray alloc]initWithObjects:#"RB Forum 2013",#"Agenda",#"Speakers",#"Contact",#"Map",#"Websites",#"#Responsible Biz",#"Partners",#"Sustainability",nil];
imagePaths=[[NSMutableArray alloc]initWithObjects:[UIImage imageNamed:#"RBform.png"],[UIImage imageNamed:#"agenda.png"],[UIImage imageNamed:#"speakers.png"],[UIImage imageNamed:#"contact.png"],[UIImage imageNamed:#"map.png"],[UIImage imageNamed:#"website.png"],[UIImage imageNamed:#"twitter.png"],[UIImage imageNamed:#"partners.png"],[UIImage imageNamed:#"sustainability.png"], nil];
}
number of items in collection view
(NSInteger)collectionView:(UICollectionView *)collectionView
numberOfItemsInSection:(NSInteger)section
{
return [imageLabels count];
}
create cell and reuse
(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionView *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"Cell"];
// make the cell's title the actual NSIndexPath value
UIlabel *label = (UIlabel *) [cell viewWithTag:2]
label.text = [NSString stringWithFormat:#"%#",[imageLabels objectAtIndex:indexPath.row]];
// load the image for this cell
UIImageView *imageView = (UIImageView *) [cell viewWithTag:1]
imageView.image = [imagePaths objectAtIndex:indexPath.row];
return cell;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self.collectionView registerNib:[UINib nibWithNibName:#"NewCell" bundle:nil] forCellWithReuseIdentifier:#"CELL"];
self.collectionview.dataSource = self;
self.collectionview.delegate = self;
self.imageLabels = [NSArray arrayWithObjects:#"RB Forum 2013",#"Agenda",#"Speakers",#"Contact",#"Map",#"Websites",#"#Responsible Biz",#"Partners",#"Sustainability",nil];
self.imagePaths=[NSArray arrayWithObjects::#"RBform.png",#"agenda.png",#"speakers.png",#"contact.png",#"map.png",#"website.png",#"twitter.png",#"partners.png",#"sustainability.png", nil];
}
- (NSInteger)collectionView:(UICollectionView *)collectionView
numberOfItemsInSection:(NSInteger)section
{
return [self.imageLabels count];
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
NewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"CELL" forIndexPath:indexPath];
cell.labels.text = [self.imageLabels objectAtIndex:indexPath.row]];
cell.images.image = [UIImage imageNamed:[self.imagePaths objectAtIndex:index path.row]];
return cell;
}
Related
I'm try to add UICollectionView to my custom UICollectionReusableView in runtime, in main form I have a UICollectionView(named mainView) to show first-level menus to user, when user did select cell in mainView it will expand second-level menus in foot section(and call FolderContentView::loadSubMenus method),
following is my wont work code, please help.
.h file
#interface FolderContentView : UICollectionReusableView<UICollectionViewDataSource,UICollectionViewDelegate>
-(void) loadSubMenus:(NSArray<EnabledModule*>*) subModules;
#end
.m file
#import "FolderContentView.h"
#implementation FolderContentView {
UICollectionView *_collectionView;
NSArray* _subMenus;
}
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
UICollectionViewFlowLayout* flowLayout = [[UICollectionViewFlowLayout alloc] init];
flowLayout.itemSize = CGSizeMake(100, 100);
[flowLayout setScrollDirection:UICollectionViewScrollDirectionHorizontal];
_collectionView = [[UICollectionView alloc] initWithFrame:frame collectionViewLayout:flowLayout];
[_collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:#"cell"];
_collectionView.delegate = self;
_collectionView.dataSource = self;
}
[_collectionView reloadData];
return self;
}
-(void) loadSubMenus:(NSArray<EnabledModule*>*) subModules {
if(subModules != nil) {
_subMenus = [subModules copy];
} else {
_subMenus = nil;
}
[_collectionView reloadData];
}
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return _subMenus!=nil?_subMenus.count:0;
}
-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
return 1;
}
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell = [collectionView
dequeueReusableCellWithReuseIdentifier:#"cell"
forIndexPath:indexPath];
if(!cell){
cell=[[UICollectionViewCell alloc]init];
}
EnabledModule *model = _subMenus[indexPath.row];
cell.hidden = !model.enabled;
UILabel *lblText = [[UILabel alloc] init];
lblText.text = model.moduleName;
[cell.contentView addSubview:lblText];
return cell;
}
#end
try reloadData from main thread, it's wont work.
set bp to numberOfItemsInSection numberOfItemsInSection, not hint.
try to set delegate and dataSource to my mainView's controller, not work too.
What's 'reloadData not work' actually means? Did the delegate methods run correctly or nothing happen?
1.Maybe you should check the codes 'add UICollectionView to my custom UICollectionReusableView in runtime'.
2.Maybe you forgot to do:
[self addSubview:_collectionView];
3.The 'cell' will not be nil in this code:
UICollectionViewCell *cell = [collectionView
dequeueReusableCellWithReuseIdentifier:#"cell"
forIndexPath:indexPath];
if(!cell){
cell=[[UICollectionViewCell alloc]init];
}
4.Don't do this:
[cell.contentView addSubview:lblText];
Use subClass of UICollectionViewCell instead.
I have two UICollectionViews in a single UIViewController. I am separating them by tag number so that I can use the data source and delegate methods for both. However, when I run the code it crashes with the Exception:
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'UICollectionView received layout attributes for a cell with an index path that does not exist: <NSIndexPath: 0xc000000000200016> {length = 2, path = 0 - 1}'.
I looked this up in the forum and most people say you need to invalidate then reload the UIControllerView but in my case this is not working.
Anyone have idea how to fix this issue ?
Here is my code:
-(void)viewDidLoad {
self.socialMediaGrayIcons = [[NSMutableArray alloc] initWithObjects:[UIImage imageNamed:#"fb-gray.png"],
[UIImage imageNamed:#"twitter-gray.png"],
[UIImage imageNamed:#"insta-gray.png"],
[UIImage imageNamed:#"sms-gray.png"],
[UIImage imageNamed:#"email-gray.png"], nil];
// setup collection view
self.avatarCollectionView.tag = 200;
self.socialMediaCollectionView.tag = 201;
UINib *cellNib = [UINib nibWithNibName:#"NibCell" bundle:nil];
[self.avatarCollectionView registerNib:cellNib forCellWithReuseIdentifier:#"cvCell"];
[self.socialMediaCollectionView registerNib:cellNib forCellWithReuseIdentifier:#"smCell"];
// setup collection view layout
UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
[flowLayout setItemSize:CGSizeMake(40, 40)];
[flowLayout setScrollDirection:UICollectionViewScrollDirectionHorizontal];
[self.avatarCollectionView setCollectionViewLayout:flowLayout];
[self.socialMediaCollectionView setCollectionViewLayout:flowLayout];
[self.avatarCollectionView reloadData];
[self.avatarCollectionView.collectionViewLayout invalidateLayout];
[self.socialMediaCollectionView reloadData];
[self.socialMediaCollectionView.collectionViewLayout invalidateLayout];
}
....
#pragma mark UICollectionView DataSource and Delegate mathods
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
return 1;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
if (collectionView.tag == 200)
{
return self.children.count;
} else if (collectionView.tag == 201){
return self.socialMediaGrayIcons.count;
}
return 1;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell;
if (collectionView.tag == 200)
{
static NSString *cellIdentifier = #"cvCell";
cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];
Child *currentChild = [self.children objectAtIndex:indexPath.row];
UIImage *curImage = [UIImage imageWithData:currentChild.thumbnail];
UIImageView *thumbView = (UIImageView *)[cell viewWithTag:100];
if (curImage != nil)
{
[thumbView setImage:curImage];
}
} else if (collectionView.tag == 201){
static NSString *cellIdentifier = #"smCell";
cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];
UIImage *curImage = (UIImage*) [self.socialMediaGrayIcons objectAtIndex:indexPath.row];
UIImageView *thumbView = (UIImageView *)[cell viewWithTag:101];
if (curImage != nil)
{
[thumbView setImage:curImage];
}
}
return cell;
}
Taking #Paulw's good advice looks like this:
#property(weak,nonatomic) IBOutlet UICollectionView *collectionViewA;
#property(weak,nonatomic) IBOutlet UICollectionView *collectionViewB;
Your datasource methods have to be religious about always dividing in two branches of a conditional based on the collection view they were passed, and always using one datasource array in one and the other in the other.
You can enforce this religion by always getting your datasource via a convenience method, like this...
- (NSArray *)datasourceForCollectionView:(UICollectionView *)collectionView {
if (collectionView == self.collectionViewA) {
return self.children;
} else { // NOTICE - no else-if, there's no other valid condition
return self.socialMediaGrayIcons;
}
}
Use it everywhere, as in...
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return [self datasourceForCollectionView:collectionView].count;
}
I have a UICollectionView that use a custom cell:
[_collectionView registerNib:[UINib nibWithNibName:#"CollectionViewCell" bundle:nil] forCellWithReuseIdentifier:#"cellIdentifier"];
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
CollectionViewCell *cell = (CollectionViewCell *)[collectionView dequeueReusableCellWithReuseIdentifier:#"cellIdentifier" forIndexPath:indexPath];
cell.articolo = [_array objectAtIndex:indexPath.row];
I want to pass the object articolo to my cell, so I create a property:
#property (strong, nonatomic) NSMutableDictionary *articolo;
but if I try to read the property in one of this method:
#implementation CollectionViewCell
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {NSLog(#"Articolo: %#",_articolo);}
return self;
}
- (id)initWithCoder:(NSCoder*)aDecoder
{
self = [super initWithCoder:aDecoder];
if(self) {NSLog(#"Articolo: %#",_articolo);}
return self;
}
- (void) awakeFromNib
{
[super awakeFromNib];
NSLog(#"Articolo: %#",_articolo);
}
I get always a null value, where is the error? how can I pass this object to my cell?
Your code is perfect, you will always get null value in any of the above method because it is called when your cell is initialized.
You can get value by putting setter method like this.
-(void)setArticolo:(NSMutableDictionary *)articolo {
_articolo = articolo;
}
Try this, it may help u.
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
CollectionViewCell *cell = (CollectionViewCell *)[collectionView dequeueReusableCellWithReuseIdentifier:#"cellIdentifier" forIndexPath:indexPath];
cell.articolo =[[NSMutableDictionary alloc] initWithDictionary:[_array objectAtIndex:indexPath.row]];
return cell;
}
Trying to keep reference in arrays of all views that being added to collection view .
So what happens, is that i have this array with the data, but when i scroll down the collection, it calls the reusable cells function ,and try to add them again to my array ,although i am checking if they are there before adding them again :
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
UICollectionViewCell *cell=[collectionView dequeueReusableCellWithReuseIdentifier:#"cellIdentifier" forIndexPath:indexPath];
//quantity
UILabel *quantityL=[[UILabel alloc] initWithFrame:CGRectMake(cell.frame.size.width/10,cell.frame.size.width/10, cell.frame.size.width/5,cell.frame.size.width/5)];
quantityL.text=[NSString stringWithFormat:#"%d",quantity];
quantityL.font=[UIFont fontWithName:[Globals sharedGlobals].titleFont size:[Globals sharedGlobals].badgeSize];
quantityL.textAlignment=NSTextAlignmentCenter;
//more and more stuff
[cell addSubview:quantityL]; //add to cell
if(![allQuantities containsObject:quantityL]) //check if already in array!
[allQuantities addObject:quantityL]; //add to array
i can see that allQuantities array is changing its size... why ?
To properly reuse and set frames: code for your controller:
#define kMyCellIdentifier #"kMyCellIdentifier"
- (void)viewDidLoad {
[super viewDidLoad];
//...
[self.collectionView setDelegate:self];
[self.collectionView setDataSource:self];
[self.collectionView registerClass:[MyCollectionViewCell class] forCellWithReuseIdentifier:kMyCellIdentifier];
}
#pragma mark - UICollectionViewDelegate && UICollectionViewDataSource
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
MyCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:kMyCellIdentifier forIndexPath:indexPath];
[cell.textLabel setText:#"blah"];
return cell;
}
And your cell subclass:
#interface MyCollectionViewCell : UICollectionViewCell
#property(nonatomic, readonly) UILabel *textLabel;
#end
#implementation MyCollectionViewCell
- (id)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
_textLabel = [[UILabel alloc] init];
[self.textLabel setTextAlignment:NSTextAlignmentCenter];
[self.contentView addSubview:self.textLabel];
}
return self;
}
- (void)layoutSubviews {
[super layoutSubviews];
CGRect rect = self.contentView.bounds;
[self.textLabel setFrame:rect];
}
the method
-(void)prepareForReuse
In my collection view cell is never called - leading me to suspect that the UICollectionView is not dequeuing cells properly. This is causing lagyness and memory issues.
I've set up my collectionView as follows:
static NSString *cellIdentifier = #"Mycell";
-(void)initMyView
{
[self.collectionView registerClass:[UrlLoadableCollectionViewCell class] forCellWithReuseIdentifier:cellIdentifier];
}
-(UICollectionViewCell*)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UrlLoadableCollectionViewCell *cell = [self.collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:index];
if (cell.contentView.frame.size.width < 100) // tried removing this as well but didn't help
{
cell.layer.shouldRasterize = YES;
cell.layer.rasterizationScale = [UIScreen mainScreen].scale;
} else {
cell.layer.shouldRasterize = NO;
}
// prepare cell
}
EDIT
Additional Code
static NSString *cellIdentifier = #"Mycell";
#interface UIThumbnailGalleryView
#property (nonatomic,strong) UICollectionView *collectionView;
#end
#implementation UIThumbnailGalleryView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self initView:frame];
}
return self;
}
-(void)initView:(CGRect)frame
{
self.collectionView = [[UICollectionView alloc] initWithFrame:self.bounds collectionViewLayout:[self getGalleryLayout]];
[self.collectionView registerClass:[UrlLoadableCollectionViewCell class] forCellWithReuseIdentifier:cellIdentifier];
self.collectionView.delegate = self;
self.collectionView.dataSource = self;
self.collectionView.autoresizingMask = UIViewAutoresizingFlexibleHeight;
[self addSubview:self.collectionView];
self.collectionView.backgroundColor = [UIColor blackColor];
[self.collectionView setShowsHorizontalScrollIndicator:NO];
[self.collectionView setShowsVerticalScrollIndicator:NO];
}
-(UICollectionViewCell*)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UrlLoadableCollectionViewCell *cell = [self.dequeueReusableCellAtIndex:indexPath];
}
-(UrlLoadableCollectionViewCell *)dequeueReusableCellAtIndex:(NSIndexPath *)index
{
UrlLoadableCollectionViewCell *cell = (UrlLoadableCollectionViewCell *)[self.collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:index];
return cell;
}
-(UICollectionViewFlowLayout *)getGalleryLayout
{
UICollectionViewFlowLayout *galleryLayout = [[UICollectionViewFlowLayout alloc] init];
[galleryLayout setItemSize:CGSizeMake(77, 77)];
galleryLayout.minimumInteritemSpacing = 3.0;
galleryLayout.minimumLineSpacing = 3.0;
// iOS 6 - might need to uncomment
//[galleryLayout setSectionInset:UIEdgeInsetsMake(44,5, 44, 5)];
return galleryLayout;
}
Please post a screenshot of the xib/scene that contains your UICollectionViewCell showing it's inspector. Or, if you're cell is constructed entirely in code, post the relevant code that registers your class with the collection view. Usually when this occurs it's because of a typo in the Cell Identifier.
You don't seem to be calling initMyView anywhere.