UICollectionViewCell does not autosize subviews at first appearance - uicollectionview

With XCode 6 and iOS 8 I encountered the problem that UICollectionViewCells does not autolayout / autoresize the subviews at first appearance. Once they have been shown and the cell is reused everything is fine.

I put
[cell layoutIfNeeded];
after the dequeueReusableCellWithReuseIdentifier-Statement and everything was fine again.

I had the same issue. I tried to put [cell layoutIfNeeded];, but when I refresh the tableview, not all the cells are refreshed.
With the code [cell layoutSubviews]; just before returning the cell, all cells are updated every time. Here is the complete piece of code
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
MyCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:kCellID forIndexPath:indexPath];
...
[cell layoutSubviews];
return cell;
}

Related

How to change the background colour of a UICollectionViewCell based on a given value

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.

Showing a specific cell each scroll back on UICollectionView

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

iOS set selected background to table row after reload data?

I have following issue: I have a UITableView.If you click on a cell, a button is added on cell. No Problem till now... but: After adding button i want the TableView (after its reload) to select the just edited (or added) TableCell.
I've tried this in cellForRowAtIndexPath method
if (bool) {
[cell setSelected:YES animated:YES];
}
UIView *bgColorView = [[UIView alloc] init];
[bgColorView setBackgroundColor:[UIColor colorWithRed:34/255.0 green:139/255.0 blue:34/255.0 alpha:1.0]];
[cell setSelectedBackgroundView:bgColorView];
[bgColorView release];
return cell;
But it didn't work.
Any suggestion or sample code would be appreciated. Thanks .
For the standard selection you use the following method, described at UITableView reference docs
- (void)selectRowAtIndexPath:(NSIndexPath *)indexPath animated:(BOOL)animated scrollPosition:(UITableViewScrollPosition)scrollPosition
Your design might be improved if you use the custom cell storing information of selection count, that is much better than reloading the table and adding a lot of cell logic outside of the cell.
Why are you using
[tableView reloadData];
You can access the selected cell properties and controls without reloading the data using:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath;
Here is some code that can help you:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
CustomTableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
[cell.myButton setHidden:false];
}

UICollectionView cellForItemAtIndexPath not registering cell

I am trying to use UICollectionViewCell, since all I want to display is an image. I can add the image to the cell using UIColor colorWithImage: on the UICollectionViewCell's contentView property.
In my loadView method, I am registering the cell as follows:
[self.collectionView registerClass:[ImageCell class] forCellWithReuseIdentifier:#"MyCell"];
Below is my cellForItemAtIndexPath method:
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"MyCell" forIndexPath:indexPath];
// cell customization
return cell;
}
When I run it, as soon as it hits the dequeue line, it crashes with the following error:
*** Assertion failure in -[UICollectionView _dequeueReusableViewOfKind:withIdentifier:forIndexPath:]
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'could not dequeue a view of kind: UICollectionElementKindCell with identifier MyCell - must register a nib or a class for the identifier or connect a prototype cell in a storyboard'
I tired setting up a custom cell, and used it as the class and I got the same error. My custom cell subclassed UICollectionViewCell and had nothing implemented, except for the default initWithFrame. That is because I wanted to just change the background colour of the view. I am not sure what the problem is but could someone please take a look at my code and help me? I've been trying to figure this out for quite a while with absolutely no luck at all.
If you just want to display an image, you don't need to do any subclassing, you can set the cell's backgroundColor with colorWithPatternImage:. Register the class like this:
[self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:#"Cell"];
Then use it like so:
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"Cell" forIndexPath:indexPath];
cell.backgroundColor = [UIColor colorWithPatternImage:[self.results objectAtIndex:indexPath.row]];
return cell;
}
In this example, results is an array of UIImages.
If you are using xib in applivation then add following in your viewdidLoad method
[self.myCollectionView registerNib:[UINib nibWithNibName:#"CollectionViewCell" bundle:nil] forCellWithReuseIdentifier:#"CellIdentifier"];
otherwise If you using storyboard add following
[self.myCollectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:#"CellIdentifier"];
Finally add this (If not)
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"CellIdentifier" forIndexPath:indexPath];
return cell;
}
Hope above will help.
Try setting a breakpoint on
[self.collectionView registerClass:[ImageCell class] forCellWithReuseIdentifier:#"MyCell"];
I would guess your loadView (did you mean viewDidLoad?) method is not being called, so the class is never registered with the collectionView.
if your collection view is connected on storyboard and the delegate and datasource is set there, and you provide the necessary methods for the datasource and delegate, then adding the register call makes the
- (UICollectionViewCell *)collectionView:(UICollectionView *)cv cellForItemAtIndexPath:(NSIndexPath *)indexPath
return a UICollectionView instead of your own subclass of it. So do either but not both.
set your cell identifier name as in code

UITableViewCell with Checkmark not visible

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];