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];
}
I tried to use two UICollectionViews in a single ViewController. Application crashed with the following error
reason: 'could not dequeue a view of kind: UICollectionElementKindCell with identifier ItemCell - must register a nib or a class for the identifier or connect a prototype cell in a storyboard
This is my implementation how looks like
HomeViewController.h
UICollectionView *colloctionViewItems;
UICollectionView *colloctionViewCats;
#property (nonatomic, retain) IBOutlet UICollectionView *colloctionViewItems;
#property (nonatomic, retain) IBOutlet UICollectionView *colloctionViewCats;
HomeViewController.m
#synthesize colloctionViewCats, colloctionViewItems;
- (void)viewDidLoad{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
// read ItemList plist
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
NSDictionary *dicCats = [appDelegate readPlistIntoDictWithFile:#"CatagoryList.plist"];
// arrCategories
arrCats = [[NSArray alloc]initWithArray:[dicCats objectForKey:#"Catagories"]];
[self.colloctionViewItems registerClass:[ItemCell class] forCellWithReuseIdentifier:#"ItemCell"];
[self.colloctionViewCats registerClass:[CatCell class] forCellWithReuseIdentifier:#"CatCell"];
[colloctionViewItems reloadData];
[colloctionViewCats reloadData];
}
#pragma mark for Collection View Delegate methods
- (NSInteger)numberOfSectionsInCollectionView: (UICollectionView *)collectionView
{
return 1;
}
- (NSInteger)collectionView:(UICollectionView *)view numberOfItemsInSection:(NSInteger)section
{
if(view == colloctionViewItems){
return [arrCats count];
}
if(view == colloctionViewCats){
return [arrCats count];
}
return 0;
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section
{
return CGSizeZero;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)cv cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
ItemCell *iCell = [cv dequeueReusableCellWithReuseIdentifier:#"ItemCell" forIndexPath:indexPath];
CatCell *cCell = [cv dequeueReusableCellWithReuseIdentifier:#"CatCell" forIndexPath:indexPath];
if(cv == colloctionViewItems){
iCell.lblBtnTitle.text = [arrCats objectAtIndex:indexPath.row];
return iCell;
}
if(cv == colloctionViewCats){
cCell.lblBtnTitle.text = [arrCats objectAtIndex:indexPath.row];
return cCell;
}
return iCell;
}
If I removed one UICollectionView, all works fine. Any ideas please.
FYI: I have created Custom Collection Cell class as "ItemCell" and "CatCell" correctly (without using nibs)
It's because you dequeue both cell at the same time, even if the collection view hasn't contain the right cell. You should first check which collection view is asking about cell and after that dequeue the right one:
- (UICollectionViewCell *)collectionView:(UICollectionView *)cv cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
if(cv == colloctionViewItems){
// Item collection view contain item cell so you can safety dequeue it.
// if you try to dequeue CatCell it will fail this is why you had this issue before
ItemCell *iCell = [cv dequeueReusableCellWithReuseIdentifier:#"ItemCell" forIndexPath:indexPath];
iCell.lblBtnTitle.text = [arrCats objectAtIndex:indexPath.row];
return iCell;
}
if(cv == colloctionViewCats){
CatCell *cCell = [cv dequeueReusableCellWithReuseIdentifier:#"CatCell" forIndexPath:indexPath];
cCell.lblBtnTitle.text = [arrCats objectAtIndex:indexPath.row];
return cCell;
}
return nil;
}
I'm trying to create a UICollectionView with a customize nib. To do that, I'm doing the same thing I'm doing with UITableView :
MyCollectionViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
myCollectionView.delegate = self;
myCollectionView.dataSource = self;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
MyCollectionCell *cell = [MyCollectionCell newCellOrReuse:collectionView atIndexPath:indexPath];
return cell;
}
MyCollectionCell.m
+ (MyCollectionCell *)newCell
{
UIViewController *vc = [[UIViewController alloc] initWithNibName:#"MyCollectionCell" bundle:nil];
MyCollectionCell *cell = (MyCollectionCell *)vc.view;
[cell initCell];
return cell;
}
+ (MyCollectionCell *)reuse:(UICollectionView *)collectionView atIndexPath:(NSIndexPath *)indexPath
{
NSString *rid = #"MyCollectionCell";
return (MyCollectionCell *)[collectionView dequeueReusableCellWithReuseIdentifier:rid forIndexPath:indexPath];
}
+ (MyCollectionCell *)newCellOrReuse:(UICollectionView *)collectionView atIndexPath:(NSIndexPath *)indexPath
{
MyCollectionCell *cell = [MyCollectionCell reuse:collectionView atIndexPath:indexPath];
if (!cell) cell = [MyCollectionCell newCell];
return cell;
}
- (void) initCell
{
}
I get an error
*** Assertion failure in -[UICollectionView _dequeueReusableViewOfKind:withIdentifier:forIndexPath:], /SourceCache/UIKit/UIKit-2380.17/UICollectionView.m:2249
on this line
return (MyCollectionCell *)[collectionView dequeueReusableCellWithReuseIdentifier:rid forIndexPath:indexPath];
I don't really get what's happening. It hase something to do with the reuse because if I call only [MyCollectionCell newCell]; it works. Actually It works only on iOS6.
On iOS7 I get *** Assertion failure in -[UICollectionView _createPreparedCellForItemAtIndexPath:withLayoutAttributes:applyAttributes:], /SourceCache/UIKit_Sim/UIKit-2903.23/UICollectionView.m:1367
Thanks for your help !
- (void)viewDidLoad {
[super viewDidLoad];
myCollectionView.delegate = self;
myCollectionView.dataSource = self;
[collectionView registerNib:[UINib nibWithNibName:#"MyCollectionCell" bundle:nil] forCellWithReuseIdentifier:#"MyCollectionCell"];
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
NSString *rid = #"MyCollectionCell";
return (MyCollectionCell *)[collectionView dequeueReusableCellWithReuseIdentifier:rid forIndexPath:indexPath];
}
Then in MyCollectionCell.m do away with all your class methods and call initCell from awakeFromNib. i.e.:
-(void)awakeFromNib {
[super awakeFromNib];
[self initCell];
}
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;
}
I am configuring a UICollectionViewCell in a subclass, it adds 2 subviews to the contentView property, both are UIImageView and both have the hidden property set to YES. These subviews are "checked" and "unchecked" images that overlay the primary UIImageView in the cell to indicate whether or not the current cell is selected using UICollectionView's "multiple select" feature.
When the cell is tapped, collectionView:didSelectItemAtIndexPath: is called on the delegate, and I'd like to setHidden:NO on the "checked" UIImageView. Calling this on the cell does nothing at all -- the cell is seemingly locked in its originally drawn state.
Is it possible to make changes to a cell outside collectionView:cellForItemAtIndexPath:? I have tried manually adding subviews within collectionView:didSelectItemAtIndexPath:, but it just makes absolutely no change to the UI. I have verified that the delegate method is getting called, it's just not making my cell changes.
- (void) collectionView(UICollectionView *)cv didSelectItemAtIndexPath(NSIndexPath *)indexPath {
ShotCell *cell = [self collectionView:cv cellForItemAtIndexPath:indexPath];
UILabel *testLabel = UILabel.alloc.init;
testLabel.text = #"FooBar";
testLabel.sizeToFit;
[cell.contentView.addSubview testLabel];
}
The way you're trying to do this is incorrect. You need to keep a reference to the selected cell or cells in a property. In this example, I use an array to hold index paths of the selected cells, then check whether the index path passed in to cellForItemAtIndexPath is contained in that array. I unselect the cell if you click on one that's already selected:
#interface ViewController ()
#property (strong,nonatomic) NSArray *theData;
#property (strong,nonatomic) NSMutableArray *paths;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.paths = [NSMutableArray new];
self.theData = #[#"One",#"Two",#"Three",#"Four",#"Five",#"Six",#"Seven",#"Eight"];
[self.collectionView registerNib:[UINib nibWithNibName:#"CVCell" bundle:nil] forCellWithReuseIdentifier:#"cvCell"];
UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
[flowLayout setScrollDirection:UICollectionViewScrollDirectionVertical];
[self.collectionView setCollectionViewLayout:flowLayout];
}
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return self.theData.count;
}
-(CVCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellIdentifier = #"cvCell";
CVCell *cell = (CVCell *) [collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];
cell.backgroundColor = [UIColor whiteColor];
cell.label.text = self.theData[indexPath.row];
if ([self.paths containsObject:indexPath]) {
[cell.iv setHidden:NO]; // iv is an IBOutlet to an image view in the custom cell
}else{
[cell.iv setHidden:YES];
}
return cell;
}
-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
if ([self.paths containsObject:indexPath]) {
[self.paths removeObject:indexPath];
}else{
[self.paths addObject:indexPath];
}
[self.collectionView reloadItemsAtIndexPaths:#[indexPath]];
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
return CGSizeMake(150, 150);
}