How to save state of UICollectionViewCell - objective-c

Please help me, how can I save state of UICollectionViewCell. For example: I have cells with UIWebView and when I dequeueReusableCellWithReuseIdentifier:forIndexPath: returned wrong cell, not for this indexPath and after it UIWebView content will reloaded for correct indexPath with twitches. Thanks!
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
NewsCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"NEWS_CELL" forIndexPath:indexPath];
if (!cell.isShowed) { // I just added boolean property
cell.isShowed = YES;
/*** some init actions ***/
}
return cell;
}
If I use this method, cells with cell.isShowed == YES return on wrong indexPath. But if I not use cell.isShowed content of UIWebView will reloaded in every showing cell
Sorry for my english :)

See what Apple's UIWebView Class Reference say:
Important: You should not embed UIWebView or UITableView objects in
UIScrollView objects. If you do so, unexpected behavior can result
because touch events for the two objects can be mixed up and wrongly
handled.
But UICollectionView inherits from UIScrollView. So you need to redesign your architecture.

Related

custom cell for UICollectionView

I need to create an app which has a list of items, each item has an image a title, a subtitle a price and a description and I need 2 items per line (so I can't use a UITableView)
Is it possible to use a UICollectionView with custom cell in order to have the result I want or should I search another solution?
The custom cell layout should be like this:
You totally can !
Just create your custom UICollectionViewCell, then go in the "cellForItemAtIndexPath" method in order to use it.
Hope this help :)
1, create a xib file in the subclass of UIcollectionViewCell
2, register your xib in controller's viewdidload fun
[mCollectionView registerNib:[UINib nibWithNibName:#"CollectionViewCell" bundle:nil] forCellWithReuseIdentifier:#"Cell"];
3,
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath;
{
CollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"Cell" forIndexPath:indexPath];
return cell;
}
You can definitely customise your UICollectionView's Cell. But you will have to do following steps as well:
Register your Custom Cell to your collection view :
[self.collectionView registerClass:[YourCustomClass class]
forCellWithReuseIdentifier:#"CustomCell"];
Secondly, inside your method : cellForItemAtIndexPath, you will have to call custom cell like this (as you do in tableView's custom cell too):
YourCustomClass *cell = (YourCustomClass *)[collectionView
dequeueReusableCellWithReuseIdentifier:#"CustomCell" forIndexPath:indexPath];
Here is a tutorial to make custom UICollectionView Cell

UICollectionView, Images inside a cell does not load until the cell is scrolled off screen

Using Xcode 6 beta 6, I have used a standard View Controller and placed a Collection view into it. Following this, I have added a prototype cell from which an array on the CollectionViewController.m file provides the images.
While the images do appear, they do not load until after that cell has been scrolled off the screen and then back on. This is stopping any images from loading when the app opens until the user scrolls down.
The images are stored locally in the file, not a Database.
Despite the lack of images, I have linked the cells to another view controller, and even though no image is displayed, the segue still operates.
Thanks for any help in advance.
I guess you are setting the UIImage on the cell image view out of the main thread. Wrap the setter code into a following snippet:
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
cell.imageView.image = {UIImage object you've got};
}];
Optionally you could also try different, single-line replacement approach, if possible:
[cell.imageView performSelectorOnMainThread:#selector(setImage:) withObject:{UIImage object} waitUntilDone:NO];
I can't find what kind of cell you mean in fact; in every case, apply the same on a particular target image view, no matter if it's a part of your cell as a property or not.
you should use willDisplayCell method to assign image.
first initial image then create cell.
here is the code :
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"cell" forIndexPath:indexPath];
return cell;}
-(void)collectionView:(UICollectionView *)collectionView willDisplayCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath{
UIImageView *imageView = (UIImageView *)[cell viewWithTag:100];
imageView.image = images[indexPath.row];}
And don't forget to reload collection view after your data is ready to be loaded:
[_myCollection reloadData];

AVAudioPlayer in cell, how to not release?

I've a collection view with custom cell class.
In each cell I've a player with a specific sound.
When made an Button and link to my code with an IBOutlet, it's doesn't fire even with the fact I have userInteractionEnabled = YES in all my views.
So I decided to play the sound in the collection view controller.
In my cell the player has a property
#property (strong, nonatomic) AVAudioPlayer *voicePlayer;
Then in the collection I have:
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
LHFriendVoiceCollectionViewCell *cell = [self.collectionView dequeueReusableCellWithReuseIdentifier:#"LHFriendVoiceCollectionViewCell" forIndexPath:indexPath];
LHFriendVoiceObject *currentFriendVoice = [[LHFriendVoiceObject alloc] initWithNSDictionnary:[self.friendsArray objectAtIndex:indexPath.row]];
[cell hydrateWithFriendVoiceObject:currentFriendVoice];
[cell.voicePlayer prepareToPlay];
//[self.voicesArray addObject:cell.voicePlayer]; tried to stock them in array but doesn't work
return cell;
}
If I play the sound in this method it's work, but I want the sound to be played when I select the cell.
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath: (NSIndexPath *)indexPath {
LHFriendVoiceCollectionViewCell *cell =
[self.collectionView dequeueReusableCellWithReuseIdentifier:#"LHFriendVoiceCollectionViewCell" forIndexPath:indexPath];
[cell.voicePlayer play];
}
Here the sound doesn't play because voicePlayer is nil.
How I can keep my players ?
This code is the problem:
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath: (NSIndexPath *)indexPath {
LHFriendVoiceCollectionViewCell *cell =
[self.collectionView dequeueReusableCellWithReuseIdentifier:#"LHFriendVoiceCollectionViewCell" forIndexPath:indexPath];
[cell.voicePlayer play];
}
That first line is wrong. You are calling dequeue. Big mistake! It makes a completely new cell. Do not make a new cell like that! Obviously that new cell will not have any AVAudioPlayer in it.
You already have a cell; it just got selected. Use the indexPath and cellForItemAtIndexPath: to learn out which cell got selected. That is the one you want to talk to.
PS You really should figure out why the button approach didn't work, but it's no big deal at this point.

UICollectionViewCell reflection - appropriate time for taking the cells' snapshot image

I'd like to add reflection to my collection view's cells. I have the method that creates a reflection, but I don't know the correct time to create the snapshot.
I have tried doing it in the collection view's -viewWillAppear:, but the cell's contentView has zero-sized frames for its subviews. I have also tried taking the snapshot during the cell's -layoutSubviews, but the subview frames are still 0.
At what point is the cell's layout set so I can take the snapshot?
The snapshot should be taken after the cell has been added to the collection view, and after the cell has been dequeued by the collection view data source. This ensures the snapshot will be up to date, containing the cell's content view at the correct moment (when it's about to be added to the collection view, and after it has just been dequeued):
CollectionViewCell.m
- (void)didMoveToSuperview {
[self updateSnapshotImage];
}
CollectionViewController.m
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath;
{
CollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"cellID" forIndexPath:indexPath];
[cell updateSnapshotImage];
return cell;
}

Confusion with storyboard and UITableView data source: How to display text in a cell

So I've been given an assignment in my Mobile apps class: make a color game app for the iphone.(The description of how to game works is at the top of the pasted viewcontroller.h file below.)
I'm very new to Objective-C and cocoa, but have managed to troubleshoot and fix a lot of things in this app. The problem I have right now is that I don't know how to properly initialize and send UITableViewCells to the view. I'm confused because all of the tutorials I've found online use datasource methods to change different attributes of the UITableView and the cells as well. I'm not sure how these methods will interact with the controls I've already placed. I'm confused because I added them by the storyboard file, not by defining tableview attributes with datasource code.
My immediate issue is that my program won't display the proper text to the cells textlabel and detailtextlabel.
I've looked everywhere online for UITableView and UITableViewCell tutorials, but they are all from years ago and I'm not sure if the advent of the storyboard has changed the way I would treat these controls.
All of the code I've written is either in the viewcontroller.m or viewcontroller.h files.
The method within ViewController.m file, that should call the cell and display text and detail text:
-(IBAction)enterClicked
{
//On enter- send instance colors to the colorTable row[i], perform comparisons and append the resulting symbols to the instanceResults String. Send instanceResults string to the resultTable row[i]. When game counter reaches 6, gameOver. If on comparisons check, the instanceColors are the same as the gameColors, then the player wins.
[self checkForLoss];
if(!self.gameOver)
{
resultOfGuess = [self comparePlayerInputToGameColors:guessColors];
[listOfGuesses addObject:guessColors];
[listOfOutcomes addObject:resultOfGuess];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:_numberOfTurnsPlayed inSection:0];
UITableViewCell *thisCell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier];
thisCell.textLabel.text = [self.listOfGuesses lastObject];
thisCell.detailTextLabel.text = [self.listOfOutcomes lastObject];
[guessColors setString:#""];
if([self checkForWin:resultOfGuess])
[UpdateLabel setText:#"You have won!"];
else
[UpdateLabel setText:#""];
self.colorCounter = 0;
self.isStepOne = YES;
_numberOfTurnsPlayed++;
}
else
{
if([self checkForLoss])
[UpdateLabel setText:#"You have lost!"];
}
}
The UITableView DataSource Methods I've called at the bottom of the viewcontroller.m file:
#pragma mark - UITableViewDataSource protocol
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
if(section == 0)
return #"Guesses: Results:";
return 0;
}
-(NSInteger) numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
-(NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 6;
}
-(UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier];
}
return cell;
}
So my questions are: Can I change a control's properties with datasource methods, if I created the controls through the storyboard? How do I properly display the text in a uitableview's cells?
Edit/update: Thank you, I've used your advice jrturton, but now I've found something peculiar that may be the source of my problems. in my viewController.h file I've changed my header from
ViewController: UIViewController to ViewController: UITableViewController
Thinking that the datasource methods I call within the viewcontroller files have to be able to call the same methods and properties of the class that I call in the header-- Also, I see this done in other UITableView tutorial files.
The problem is that when I change the header to read-- ViewController: UITableViewController -- and I try to compile, I get this error:
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '-[UITableViewController loadView] loaded the "2-view-3" nib but didn't get a UITableView.'
It compiles fine if I use just :UIViewController in the header file though.
Any ideas?
Further update: I''ve noticed within my storyboard that the only available ViewController object is a UIViewController object, while in the other tutorial files I've seen, this ViewController object is a UITableViewController object. I imagine this is my problem, but I can't seem to switch my UIViewController object to a UITableViewController. All I can do is create a new one, which isn't what I want, I imagine.
Your action method should update the data model (which I think it does, since it changes your listOfGuesses array). You then need to let your table view know that you have added or updated rows so that it can re-load them for you - check the UITableView documentation for reloading data or specific rows.
Creating a cell outside of the datasource methods isn't going to let that cell appear in your table.
At the moment I'm guessing you have 6 empty cells in your table view? You need to populate the text and detail labels in your cellForRowAtIndexPath method. The difference now there are storyboards is that you don't need to do the if (cell == nil) bit, as long as you have set the re-use identifier in your storyboard prototype cell then it will do all that for you. So your cellForRowAtIndexPath method can be reduced to:
-(UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath
{
// This will dequeue or create a new cell based on the prototype in your storyboard
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell"];
// Put your actual configuration here based on your model array
cell.textLabel.text = #"Hello";
return cell;
}
Further hints (this is homework so I'm not giving full samples)
'indexPath.row` in the above method will give you the index from your model array that the cell refers to
You have defined the table as having 6 rows, but you are adding items to your model arrays as you go - so when the table asks for row 5, and your model only has 3 entries, you need to deal with this. Consider changing the number of rows in the table dynamically and using table view methods to indicate that new rows have been added. Again, see the UITableView documentation for this.
Typically the text is set in each cell by accessing the setText property:
[[cell textLabel] setText:#"static string"];
or
[[cell textLabel] setText:someNSString];
or with .dot notation
cell.textLabel.text = someNSString;
return cell;
BTW this is done in the method:
-(UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath: