Table view cell background goes white when deleting a cell - iOS - objective-c

I have an iOS app with a UITableView, I have noticed that the cell background colour flashes white when the user selects the Delete button.
In the editActionsForRowAtIndexPath method, I have created two cell buttons: Edit and Delete. The first button's style is set to UITableViewRowActionStyleNormal. however the second button's style is set to UITableViewRowActionStyleDestructive - I have noticed that this issue only occurs when then style is set to destructive. Does anyone know why this is happening?
Here is the method I am using to set the cell action buttons:
-(NSArray *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath {
// Create the table view cell edit buttons.
UITableViewRowAction *editButton = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleNormal title:#"Edit" handler:^(UITableViewRowAction *action, NSIndexPath *indexPath) {
// Edit the selected action.
[self editAction:indexPath];
}];
editButton.backgroundColor = [UIColor blueColor];
UITableViewRowAction *deleteButton = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDestructive title:#"Delete" handler:^(UITableViewRowAction *action, NSIndexPath *indexPath) {
// Delete the selected action.
[tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade];
}];
return #[deleteButton, editButton];
}
The colour of the cell is normal when the user is scrolling, tapping it or when he/she selects the Edit button, but when they select the Delete button, the cell turns white as the deletion animation is occurring.
How can I fix this?

It turns out the issue I am experiencing, is due to an iOS bug. I found a solution here: https://stackoverflow.com/a/46649768/1598906
[[UITableViewCell appearance] setBackgroundColor:[UIColor clearColor]];
The above code is set in the App Delegate, it set the background color to clear, thus removing the white background view.

Before calling the deleteRowsAtIndexPaths method, you need to remove the object from the data source;
Replace this:
UITableViewRowAction *deleteButton = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDestructive title:#"Delete" handler:^(UITableViewRowAction *action, NSIndexPath *indexPath) {
// Delete the selected action.
[tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade];
}];
with something like this:
UITableViewRowAction *deleteButton = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDestructive title:#"Delete" handler:^(UITableViewRowAction *action, NSIndexPath *indexPath) {
// Delete the selected action.
[self deleteObjectAtIndexPath:indexPath];
}];
and the method to delete:
- (void)deleteObjectAtIndexPath:(NSIndexPath *)indexPath {
// remove object from data source. I assume that you have an array dataSource, or change it according with your data source
[self.dataSource removeObjectAtIndex:(indexPath.row)];
[self.tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade];
}

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.

Storyboard - static cell in Detail view - managing buttons dynamically

I've recently found a way to solve displaying a button when data exists and not when no data is in a cell. Specifically using Storyboards in a detail view (static cell). This button is a necessity on the Storyboard due to some seque wiring I've hooked up.
I placed a custom button with no background image on it, and set a tag value of the tableviewcell to 1.
Then in my implementation file I've overridden the cellForRowAtIndexPath.
My question is, while this works fine, is it performance intensive? I have only 5 cells in this MOC. Here's my code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [super tableView:tableView cellForRowAtIndexPath:indexPath];
// need to capture the section and the cell to modify....
if (cell.tag == 1){
if (self.map){
self.mapButton.enabled = YES;
self.mapLabel.text = #"Click Map for Pic Location...";
UIImage *buttonImage = [UIImage imageNamed:#"MyMap.png"];
[self.mapButton setBackgroundImage:buttonImage forState:UIControlStateNormal];
} else{
self.mapLabel.text = #"No Location found for Pic";
self.mapButton.enabled = NO;
}
}
return cell;
}

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

UITableViewCell unselectable while its accessoryView is selectable

I want to have a UITableViewCell that is not selectable while its accessory view (a UISwitch in my case) is editable.
The issue is that I have two other cells of which one needs to remain active; this is very similar to the following image of the Time/Date selector from the iOS calendar app:
http://www.theiphoneblog.com/images/stories/2009/01/photo.jpg
I cannot post the image due to being a new user.
Note that in this view the "All-day" cell cannot be selected but its UISwitch can be changed, while one of "Starts" and "Ends" cells must remain selected.
I've tried both:
[cell setUserInteractionEnabled:NO];
[cell.contentView setUserInteractionEnabled:NO];
The first one works but does not allow the switch to be changed whereas the second does not work, it allows one of the top cells to be deselected which I do not want to happen.
Implement in delegate method
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([selectablePaths contains:indexPath])
{
// cell selected
selectedPath = indexPath;
}else
{
[tableView deselectRowAtIndexPath:indexPath animated:NO];
[tableView selectRowAtIndexPath:selectedPath animated:YES scrollPosition:UITableViewScrollPositionNone];
}
}
And enable user interaction for all cells.

Add editing elements to UITableViewCell

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: