I am trying to change UICollectionViewCell data on button click(in iPad)?
How to achieve this?
How to send different array count to numberOfItemsInSection on button Click?
In my viewDidLoad:
self.collectionViewImages=[[NSMutableArray alloc]initWithObjects:#"1.jpg",#"2.jpg",#"3.jpg",nil] ;
Then in CollectionViewMethods:
-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
return 1;
}
-(NSInteger)collectionView:(UICollectionView *)collectionView
numberOfItemsInSection:(NSInteger)section
{
return [_collectionViewImages count];
}
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView
cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *myCell = [collectionView dequeueReusableCellWithReuseIdentifier:#"Cell"
forIndexPath:indexPath];
NSString *collectionViewImageName=[self.collectionViewImages objectAtIndex:indexPath.row];
UIImageView * collectionImage = (UIImageView*)[myCell viewWithTag:11];
collectionImage.image =[UIImage imageNamed:collectionViewImageName];
return myCell;
}
Then on ButtonClick--
(As there are 4-5 buttons i am collecting tag of each button in NSInteger and using that property in numberOfItemsInSection like this,
-(void)btnTapped:(id)sender{
int tag= [(UIButton *)sender tag];
NSLog(#"Button Pressed%d",tag);
_buttonIndex=tag;
//_buttonIndex is NSInteger property
//If i add object in NSMutableArray and call reloadData my UI hangs here only.
//If I empty my NSMutableArray and add new objects in it and then call reloadData, I am getting NSRangeException.
}
And now i am using this property in numberOfItemsInSection as...
if (_buttonIndex==1){
[collectionImage setImage:[UIImage imageNamed:[_array1 objectAtIndex:indexPath.row]]];
//My _array1 has 4 objects and my collectionViewImages array has 7 objects.
}
i am getting error message as
*** Terminating app due to uncaught exception 'NSRangeException',
reason: '*** -[__NSArrayM objectAtIndex:]: index 4 beyond bounds [0 .. 3]'
well you keep two array with a BOOL and based on taps you relload the UicollectionView first keep two array
Declare BOOL
BOOL isChangeData;
Ex :
self.collectionViewImages=[[NSMutableArray alloc]initWithObjects:#"1.jpg",#"2.jpg",#"3.jpg",nil] ;
self.collectionViewImages1=[[NSMutableArray alloc]initWithObjects:#"4.jpg",#"5.jpg",#"6.jpg",nil] ;
isChangeData = TRUE;
First time set original Data as Datasource
-(NSInteger)collectionView:(UICollectionView *)collectionView
numberOfItemsInSection:(NSInteger)section
{
if(isChangeData){
isChangeData = false;
return [_collectionViewImages1 count];
}
else{
isChangeData = TRUE;
return [_collectionViewImages count];
}
}
in button action Make BOOL true and reload UICOllectionView
-(IBAction)changeData:(id)sender {
[self.CollectionView reloadData];
}
Hope this Works if i did any mistake pls correct me.
I believe you're just simply asking how to add/remove data from a UICollectionView through an IBAction. You would just add an object to your UICollectionView's datasource and reload. Here is an example of adding something:
-(IBAction)addObject:(id)sender {
[self.objectArray addObject:#"new object"];
[self.myCollectionView reloadData];
}
Related
I want to call didSelectItemAtIndexPath: for particular index path but I can't call it programmatically in cellForItemAtIndexPath because collection is not yet ready, I will get cell as nil. Do we have any delegate method or any other UIView method that is called after collection view is ready?
I have tried willDisplayCell: but it is not made for relevant work, couldn't find anything else.
I want to call didSelectItemAtIndexPath:
Don't. This is a delegate method. It is called by the runtime when the user selects an item. You must never call this yourself.
You have to do it programmatically utilising your manual logics. :)
The underlying concept is that get the indexes of selected cells and reload those specific cells only.
Declare a global var
NSMutableArray array_indexpath;
in your did select method add indexes of selected cells.
-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
array_indexpath=[[NSMutableArray alloc]init];
[array_indexpath addObject:indexPath];
[self.myCollectionView reloadItemsAtIndexPaths:array_indexpath];
}
and in your cell for cellForItemAtIndexPath method check the indexes and reload it as required.
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
ShubhCalendarCollectionViewCell *cell =[collectionView dequeueReusableCellWithReuseIdentifier:#"ShubhCalendarCollectionViewCell" forIndexPath:indexPath];
cell.backgroundColor=[UIColor clearColor];
if (array_indexpath.count !=0)
{
for (int i=0; i<[array_indexpath count]; i++)
{
if ([array_indexpath objectAtIndex:i] == indexPath)
{
cell.backgroundColor=[UIColor greenColor];
}
}
}
return cell;
}
Hope it helps.. Happy Coding.. :)
I’m trying to add in a new cell into my collection view, only if it has more than one item already in it. I have no worked much with collection views, and research in the docs and this site had not helped solve this issue yet. So, on my cellForItemAtIndexPath method, I do a check to see if it is populated. If not, I add the cell, like so:
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
if (self.myArray.count != 0) {
return self.myArray.count + 1;
}
else {
return self.myArray.count;
}
}
// The cell that is returned must be retrieved from a call to -dequeueReusableCellWithReuseIdentifier:forIndexPath:
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
MyNormalCollectionViewCellS *cells = (MyNormalCollectionViewCells *) [collectionView dequeueReusableCellWithReuseIdentifier:#"MyNormalCollectionViewCells” forIndexPath:indexPath];
cell.clipsToBounds = NO;
DataClass *data = [self.myArray objectAtIndex:indexPath.row];
[cells configureMyNormalCellsWith:data];
if (0 < self.myArray.count) {
UICollectionViewCell *deleteCell = [UICollectionViewCell new];
deleteCell.backgroundColor = [UIColor yellowColor];
NSArray *newData = [[NSArray alloc] initWithObjects:deleteCell, nil];
[self.myArray addObjectsFromArray:newData];
NSMutableArray *arrayWithIndexPaths = [NSMutableArray array];
[self.myCollectionView insertItemsAtIndexPaths:arrayWithIndexPaths];
return deleteCell;
}
return cell;
}
For some reason, I have an assertion being thrown, stating:
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid
number of items in section 0. The number of items contained in an
existing section after the update (7) must be equal to the number of
items contained in that section before the update (6), plus or minus
the number of items inserted or deleted from that section (0 inserted,
0 deleted) and plus or minus the number of items moved into or out of
that section (0 moved in, 0 moved out).'
Of course, the number usually varies, but it's always angry about that extra cell. Everything is fine up until I try and add it in. Now, being unfamiliar with collection views and after browsing related questions upon this site, I decided it was time to ask the pros.
Does anyone know how I should change this code in order to accomplish what I'm trying to do?
Don't modify data source in collectionView:cellForItemAtIndexPath:. Return different number of items in - collectionView:numberOfItemsInSection: instead:
- (NSInteger)collectionView:(UICollectionView *)collectionView
numberOfItemsInSection:(NSInteger)section {
if (self.dataArray.count > 0) {
return self.dataArray.count + 1;
}
else {
return 0;
}
}
In collectionView:cellForItemAtIndexPath: you should return your "normal" cell for "normal" item, and "extra" cell for that extra one, depending on the value of indexPath.row. For example:
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.row < self.dataArray.count) { // if indexPath.row is within data array bounds
// dequeue, setup and return "normal" cell
} else { // this is your "+1" cell
// dequeue, setup and return "extra" cell
}
}
I'm trying to work through the iTunes U CS193P iOS programming course. I'm running into some issues using UICollectionView to display cards as a part of the Set game implementation. I'm seeing a very odd behavior when clicking on a card causing the UICollectionView to refresh. Contents will be reordered and sometimes repeated in the view. See two examples of before and afters here.
I'm fairly certain this has to do with my UICollectionView implementation as the game logic has been tested using buttons.
Tap code in the "view controller":
- (IBAction)touchCard:(UITapGestureRecognizer *)sender {
CGPoint tapLocation = [sender locationInView:self.cardCollectionView];
NSIndexPath *indexPath = [self.cardCollectionView indexPathForItemAtPoint:tapLocation];
if (indexPath) {
[self.game chooseCardatIndex:indexPath.item];
[self updateUI];
}
}
The updateUI code:
- (void)updateUI
{
// Reload data for cardCollectionView
[self.cardCollectionView reloadData];
// For each cell within the UICollectionViewCell
for (UICollectionViewCell *cell in [self.cardCollectionView visibleCells]) {
NSIndexPath *indexPath = [self.cardCollectionView indexPathForCell:cell];
Card *card = [self.game cardAtIndex:indexPath.item];
if([card isKindOfClass:[SetCard class]]) {
SetCard *setcard = (SetCard *)card;
NSLog([NSString stringWithFormat:#"index %d updated with %d,%d,%d,%d",indexPath.item,setcard.rank,setcard.color,setcard.shape,setcard.pattern]);
// Updates individual cards for each cardCollectionView
[self updateCell:cell usingCard:card animated:YES];
}
}
}
This updates the cell view:
- (void)updateCell:(UICollectionViewCell *)cell usingCard:(Card *)card animated:(BOOL)animated
{
setCardView *cardView = ((setCardCellView *)cell).setCardV;
if([card isKindOfClass:[SetCard class]]) {
SetCard *setCard = (SetCard *)card;
// Set attributes of the card in the cardView
cardView.rank = setCard.rank;
cardView.shape = setCard.shape;
cardView.pattern = setCard.pattern;
cardView.color = setCard.color;
// Set chosen cards
cardView.selected = setCard.isChosen;
}
}
Finally the collectionView required method cellForItemAtIndexPath:
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:[self reuseIdentifier] forIndexPath:indexPath];
Card *card = [self.game cardAtIndex:indexPath.item];
[self updateCell:cell usingCard:card animated:YES];
return cell;
}
Thank you for your assistance.
When you implement a cellForRowAtIndexPath / cellForItemAtIndexPath method, you have to fully configure every cell that you get back from the dequeue method.
Your code is only configuring the cell if the card object for that row is of type SetCard. If the card object is not a SetCard, you leave the cell alone. That means that if the cell you get from your dequeue method was previously used to display a SetCard, but the card object is not a SetCard, the cell's views won't get changed, and will still show the old values.
Add an else clause to your if statement that sets the fields back to their default state if the card object is not of class SetCard.
Please can anyone help me to achieve something like this-
(developing for iPad iOS7) In UIViewController i have UITableView & UICollectionView(like splitViewController).I just want to change image in UICollectionView when i tap on UITableViewCell.(I am using button over tableViewCell and collecting index in NSInteger).
Please help me to achieve this,I am trying from so many days,but can't achieve till now. :(
Here is the code what i have done till now.
In my viewDidLoad:
self.collectionViewImages=[[NSMutableArray alloc]initWithObjects:#"1.jpg",#"2.jpg",#"3.jpg",nil] ;
Then in CollectionViewMethods:
-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
return 1;
}
-(NSInteger)collectionView:(UICollectionView *)collectionView
numberOfItemsInSection:(NSInteger)section
{
return [_collectionViewImages count];
}
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView
cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *myCell = [collectionView dequeueReusableCellWithReuseIdentifier:#"Cell"
forIndexPath:indexPath];
NSString *collectionViewImageName=[self.collectionViewImages objectAtIndex:indexPath.row];
UIImageView * collectionImage = (UIImageView*)[myCell viewWithTag:11];
collectionImage.image =[UIImage imageNamed:collectionViewImageName];
return myCell;
}
Then on ButtonClick(ofTableViewCell)--
(i am collecting tag of each button in NSInteger and using that property in numberOfItemsInSection like this,
-(void)btnTapped:(id)sender{
int tag= [(UIButton *)sender tag];
NSLog(#"Button Pressed%d",tag);
_buttonIndex=tag;
//_buttonIndex is NSInteger property
//If i add object in NSMutableArray and call reloadData my UI hangs here only.
//If I empty my NSMutableArray and add new objects in it and then call reloadData, I am getting NSRangeException.
}
And now i am using this property in numberOfItemsInSection as...
if (_buttonIndex==1){
[collectionImage setImage:[UIImage imageNamed:[_array1 objectAtIndex:indexPath.row]]];
//My _array1 has 4 objects and my collectionViewImages array has 7 objects.
}
i am getting error message as
*** Terminating app due to uncaught exception 'NSRangeException',
reason: '*** -[__NSArrayM objectAtIndex:]: index 4 beyond bounds [0 .. 3]'
Its crashing because you are trying to get an item from the array at index 4. But there are only indexes: 0,1,2,3.
Double check the contents of array1 on line (if it crashes here):
[collectionImage setImage:[UIImage imageNamed:[_array1 objectAtIndex:indexPath.row]]];
Otherwise find the other place where you call objectAtIndexand check if it crashes there.
I have a little bit problem with -[__NSArrayM objectAtIndex:]: index 6 beyond bounds [0 .. 4]' How can I show (null) If I don't have data.
Here's code
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
if ([[bookList objectAtIndex:indexPath.item]quiz_url]==[[bookList objectAtIndex:6]quiz_url]) {// This one is problem, I have `objectAtIndex:` only 0 - 5 .
// quiz_all = [[bookList objectAtIndex:indexPath.item]quiz_url];
_getQuiz6 = [[bookList objectAtIndex:6]quiz_url];
NSLog(#" test quiz6 = %#",_getQuiz6); //It's possible? Can I print `(null)` if no data.
}
...
and
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
return [bookList count];
}
I don't have data [[bookList objectAtIndex:6]quiz_url] on webservice.
There's plenty of ways you could go around this. One way to deal with it, is using "placeholder" objects to pad the content, for example, NSNull. Or you could modify your Book object and add a property like isLoaded.
Whatever method you choose, then (sticking with the NSNull);
- (UICollectionViewCell*)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
// Whatever code you have
Book *book = [bookList objectAtIndex:indexPath.item];
// NSNull is a singleton, you can safely do pointer comparison
if (book == [NSNull null])
{
// Show loading or something in the cell
cell.loadingOrSomething = YES;
// Return the cell here
return cell;
}
// book wasn't NSNull, then proceed with the rest of stuff
NSURL *url = [book quiz_url];
cell.loadingOrSomething = NO;
return cell;
}
You can use a category if you want. Somewhere in a header include this:
#interface NSArray (custom)
-(id)quizURLAtIndex:(int)index;
#end
and in a .m file you add this:
#implementation NSArray (custom)
-(id)quizURLAtIndex:(int)index{
if(index >= self.count) return nil;
else return [[self objectAtIndex:index] quiz_url];
}
#end
And from now on, whenever you want, you can call [bookList quizURLAtIndex:indexPath.item] instead of [[bookList objectAtIndex:indexPath.row] quiz_url]