I'm trying to load a custom cell each time someone scrolls up/back on my UICollectionView then if a condition is met, allow that user to see the previous items in the UICollectionView / resume normal UICollectionView behavior.
I tried subtracting the current indexpath.row, but that isn't working and I can't wrap my head around what exactly the case needs to be to make it work.
I was able to successfully get the custom cell to render as the third item (2) in the UICollectionView (shown below), but can't figure out how to make it's index path 0 and start the collection view on index path 1.
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
if (indexPath.row == 2) {
MyCustomCell *customCell = [collectionView dequeueReusableCellWithReuseIdentifier:#"customCell" forIndexPath:indexPath];
return customCell;
}
else {
PhotoCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"photo" forIndexPath:indexPath];
_obj_IndexPath = indexPath;
NSLog(#"%ld",(long)_obj_IndexPath.row);
_imageView = (UIImageView *)[cell viewWithTag:200];
_imageView.image = [UIImage imageNamed:[_imageArray objectAtIndex:indexPath.row]];
return cell;
}
}
The goal is a normal UICollectionView functionality with "full-screen" cells that scroll vertically AND during a certain condition scrolling to the previous cell is limited to only one scroll back AND that cell has a special / custom view on top of the cell content.
Any help or ideas would be awesome. Thank you!
I've updated my current code per comments below
Related
I have a view controller which contains a UICollectionView. It has re-use identifier ValveCell specified for the prototype cell. It is using a custom subclass of UICollectionViewCell called ValveViewCell.
I have put a couple of text labels on the prototype cell using the Storyboard and I can get the different values to display in multiple cells no problem. There are currently 4 cells, displaying info from 4 different valves.
All I want to do is change the background colour of the cell depending on whether the valve is turned on or off (a boolean value which I can successfully test on).
I am using this code:
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
ValveViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"ValveCell" forIndexPath:indexPath];
Valve *valve = [valveArray objectAtIndex:indexPath.row];
cell.valveID.text = [valve.valveID stringValue];
cell.valveLabel.text = valve.valveLabel;
cell.valveStatus.text = valve.status;
if ([valve isOn]) {
[cell setBackgroundColor:[UIColor greenColor]];
} else {
[cell setBackgroundColor:[UIColor redColor]];
}
return cell;
}
The problem is that it does change the background colour, but it changes every single cell's background colour instead of just the current cell. Any ideas? Thanks in advance!
Easy Fix! Put this as the first line in your method!
ValveViewCell *cell = [[ValveViewCell alloc] init]
and then change
ValveViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"ValveCell" forIndexPath:indexPath];
to
cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"ValveCell" forIndexPath:indexPath];
You're referencing the same cell for the whole collectionView so initializing each cell will fix your issue.
The content is distinct on all the cells on the first page but as we scroll down, only the UIImageView is repeated though the UILabels are distinct.
I am using [UIImageView setImageWithURL:(NSURL *)url] from AFNetworking which was included in the RestKit. Heres the implementation
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
RClubTableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:#"RClubTableViewCell"];
RClubObject * club = _clubs[indexPath.row];
[cell.clubImageView setImageWithURL:[NSURL URLWithString:club.clubImageURL]];
cell.nameLabel.text = club.clubName;
return cell;
}
Seems like iOS is somehow using the previously created cells. Would like to have completely fresh cells while scrolling.
You need to call setImageWithURL:placeholderImage: with a non-nil placeholder image to have the old image removed from the image view.
I guess you missed reallocation in your cellForRowAtIndexPath:
Your code should be something like this
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
RClubTableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:#"RClubTableViewCell"];
if(cell == nil)
{
cell = [[RClubTableViewCell alloc] init];
}
RClubObject * club = _clubs[indexPath.row];
[cell.clubImageView setImageWithURL:[NSURL URLWithString:club.clubImageURL]];
cell.nameLabel.text = club.clubName;
return cell;
}
Update :
Okay. I just had the same issue. Here what my search over google tells me : Since you are downloading the image in async and also scrolling, it gets downloaded and attached to other cells which are currently visible
Solution:
add tag to each imageView using indexpath.row
Use function setImageWithURL: placeholderImage:success:
In success block reload the cell using the tag value.
Though I haven't tested this I feel this should work. PS : Let me know if this works I also would have to do the same then :)
Yes, iOS is reusing the previously created cells. That is what this line of code does, so that the app does not have to spend the time creating a new cell from scratch:
RClubTableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:#"RClubTableViewCell"];
Clear the image from the recycled cell before adding the new image for this cell:
cell.clubImageView.image = nil;
[cell.clubImageView setImageWithURL:[NSURL URLWithString:club.clubImageURL]];
cell.nameLabel.text = club.clubName;
return cell;
Alternatively, you could create a new cell from scratch instead of dequeuing one.
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];
I've a problem with my UITableView inside PopoverController.
When I touch cell, the didSelectRowAtIndexPath function is called, and the cell accessoryType is changed. Example simplified :
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [self.listItems objectAtIndex:indexPath.row];
cell.accessoryType = UITableViewCellAccessoryCheckmark;
[self.tableView reloadData];
[self.popoverController dismissPopoverAnimated:YES];
}
It's working, the cell are checked, but it's not visible on my tableview : I can't see the blue checkmark. However, in touch state on the cell, the checkmark is visible in white (and the cell background is gray). But not visible in default state.
Do you have any idea why my checkmark are not visible in default state ?
Thanks,
Edit: Add screenshot, for a cell with accessoryType = UITableViewCellAccessoryCheckmark
This happened to me when I changed the global tint color to white. Once I realized, I went into the UITableView and change the tint color locally for just this table. Fixed.
I've tried the answer Jacky Boy - didn't help. But something was there in the deselection...
So I've tried to deselect the cell in the didSelectRowAtIndexPath: before adding the checkmark accessory:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:YES];
UITableViewCell* selectedCell = [tableView cellForRowAtIndexPath:indexPath];
if (row != _selectedRow) {
if (selectedCell.accessoryType == UITableViewCellAccessoryNone) {
selectedCell.accessoryType = UITableViewCellAccessoryCheckmark;
_selectedRow = row;
} else if (selectedCell.accessoryType == UITableViewCellAccessoryCheckmark) {
selectedCell.accessoryType = UITableViewCellAccessoryNone;
}
[tableView reloadData];
}
}
And for me it worked at last - the nice dark checkmark now is clearly visible on the cell!
Of course there is a part in cellForRowAtIndexPath: similar to described in arexx's answer.
I had a similar problem where, after reloading the row with a checkmark set as the accessory, the checkmark wouldn't be visible (but would be visible in white when the row was selected). In testing around the problem I discovered that the checkmark is always present in the cell, it's just white-on-white.
My understanding of the problem is that when I ask for the cell to be reloaded (so that I can show it with a checkmark), the existing cell is put on the reuse queue, but is at that time in a selected state (because the user just selected it). It's still in a selected state when the cell comes back off the reuse queue and you re-configure it in tableView:cellForRowAtIndexPath, and because it's selected, the accessory is set in white instead of in a visible colour.
To fix this, I added a line in tableView:cellForRowAtIndexPath to force the cell not to be selected. The accessory is now always visible when the new cell is displayed.
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// Get a reusable cell - this only works with Storyboard prototype cells
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"MyCell"];
// THE MAGIC BIT
// Force the cell to not be in a selected state.
cell.selected = NO;
// END MAGIC BIT
if (indexPathIsPathOfSelectedRow) {
// This is the selected cell, so show the checkmark accessory.
cell.accessoryType = UITableViewCellAccessoryCheckmark;
} else {
// In case we're reusing a cell that previously showed a checkmark, clear it.
cell.accessoryType = UITableViewCellAccessoryNone;
}
return cell;
}
Mine was the most stupidest reason. I had created a tableview in storyboard, with a View Controller of size 5.5 inch and forgot to apply the layout constraints.
Then I launched in a 4 inch phone, Everything looked fine except the accessory view was not visible because of tableviews width was greater than that of the phone screen. It took me 3 hours to find out my mistake.
You are reloading the UITableView so in theory the cells are recreated and this time without the checkmark. Do the following:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [self.listItems objectAtIndex:indexPath.row];
cell.accessoryType = UITableViewCellAccessoryCheckmark;
[self.popoverController dismissPopoverAnimated:YES];
}
Running under iOS 6.1, the behavior I see is a cell with a white check mark on an almost white background. This appears to be happening because the code that draws the check mark accessory believes the cell is in a highlighted state, so rather than drawing the check mark in the normal blue color, it is drawn in white.
Setting the selected state of the cell did not work for me but setting the highlighted state immediately before setting the accessory type did. With the following in place, I always get a dark blue check mark.
cell.highlighted = NO;
if (checked)
self.accessoryType = UITableViewCellAccessoryCheckmark;
else
self.accessoryType = UITableViewCellAccessoryNone;
If you want to reload Data then you should store selected Id in some variable for single selection like rowIndex and then in
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
//check index
if (rowIndex==indexPath.row)
{cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else{
cell.accessoryType = UITableViewCellAccessoryNone;
}
}
Thanks.
-(UIImageView *)checkmarkImg{
UIImage *image = [[UIImage imageNamed:#"ic_check_black_24dp.png"] changeColor:CLR_BUY];
UIImageView *checkmark = [[UIImageView alloc] initWithImage:image];
return checkmark;
}
cell.accessoryView = [self checkmarkImg];
I have a couple of rows in a table view which I like to edit.
I thought that setEditing method would give me a Edit and Delete button, but it only shows a Delete button. Because I don't have a detail view controller that's going to be pushed in didSelectRowAtIndexPath I thought I could show a couple of editing elements in the selected cell.
I need to add three buttons to specify priority on assignments: Low, High and Medium priority. This means that I have to change the height of the selected cell to make room for these buttons, I think that's rather easy to do.
What I'm wondering is if this is the correct path to choose?
I have done quite a lot research today without finding examples of how other have solved editing in a UITableViewCell. If you edit a contact in the Contacts app in the iPhone the UITableViewCells changes to enable quick and easy editing, that's what I'm looking for.
So what do you have for tips for me regarding this question?
Edit #1
My code in didSelectRowAtIndexPath is:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
Cell *selectedCell = (Cell *)[tableView cellForRowAtIndexPath: indexPath];
UIButton *btn = [UIButton buttonWithType: UIButtonTypeRoundedRect];
btn.frame = CGRectMake(0, 0, 50, 100);
btn.titleLabel.text = #"Set this item to High Priority";
btn.backgroundColor = [UIColor greenColor];
[selectedCell.contentView addSubview: btn];
self.editing = YES;
[tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject: indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
Code for heightForRowAtIndexPath:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
Cell *cell = nil;
if (self.editing)
cell = (Cell *)[tableView cellForRowAtIndexPath: indexPath];
else
cell = nil;
BOOL expandCell = NO;
NSInteger expandationHeight = 0;
if (cell != nil)
{
for (UIButton *btn in cell.contentView.subviews)
{
NSLog(#"A button was found.");
expandationHeight = 70;
expandCell = YES;
}
}
return expandationHeight + heightOfOtherElements;
}
When I click at a cell nothing happends but everything becomes disabled, I can't click any elements on the hole view. This has something to do with [tableView cellForRowAtIndexPath: indexPath], because if I uncomment that line the UI does not become disabled.
What am I doing wrong?
That's not too complicated though it requires some stuff.
You want to change the content of one cell or of all cells?
To specify a specific height for one cell, use the - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath delegate method.
It is called for each cell each time the table view is displayed. If you want to change a single row, call reloadRowsAtIndexPaths:withRowAnimation: method from UITableView. If you want to update all cells, simply use - (void)reloadData method.
You can also access a specific cell using - (UITableViewCell *)cellForRowAtIndexPath:(NSIndexPath *)indexPath method from UITableView. Then you can reconfigure it to add various elements on it, as you want.
Thus, when a cell is selected, check whether you have to edit it or not, then :
update your cell get from cellForRowAtIndexPath
be sure your method tableView:heightForRowAtIndexPath: will return the good height
tell the table view to update the view using reloadRowsAtIndexPaths:withRowAnimation: