21

I have a UITableView with cells in a Storyboard, and a segue connecting the cells to another view.

When you select a cell it displays the cell selection animation (turning the cell gray, in my case) and pushes the other view onto the screen. But when you return to the tableview, the deselection animation doesn't show at all (the reverse of the selection animation). Since I'm just using a segue, I expected this to be taken care of by default.

Is there any way to force it to show the deselection animation?

Evan Cordell
  • 4,108
  • 2
  • 31
  • 47

6 Answers6

26

This would be handled automatically if your view controller was a subclass of UITableViewController and clearsSelectedOnViewWillAppear was set to YES (which is the default value).

In your case you can do this the same exact way that UITableViewController does it. Deselect the selected row in -viewWillAppear:.

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    NSIndexPath *selectedIndexPath = [self.tableView indexPathForSelectedRow];
    [self.tableView deselectRowAtIndexPath:selectedIndexPath animated:YES];
}
Mark Adams
  • 30,776
  • 11
  • 77
  • 77
  • My view controller is a subclass of UITableViewController. The cell is deselected when it's shown, it just doesn't show an animation - it's deselected to start with. (Just in case, I tried what you suggested and it didn't work.) – Evan Cordell Dec 16 '11 at 08:03
  • Just created a sample project with a `UITableViewController` in a `UINavigationController` that pushes to another view controller. All set up using a storyboard with segues and popping the view controller displays the deselection animation. Perhaps the view of the original view controller is being unloaded so the selection state of the table is lost. This may happen in high memory pressure situations. – Mark Adams Dec 16 '11 at 08:11
  • My app is set up as you describe (but with tabs as well), and it uses Core Data. Most of the requests right now are only two or three records (for testing), so I wouldn't think it would be a drain on memory resources. – Evan Cordell Dec 16 '11 at 08:18
  • This code is correct, and there is an option directly in Interface Builder (when selecting the UITableViewController, not the TableView) "Clear on appearance". – Oli Dec 22 '11 at 19:35
  • I get the same behavior whether that option is checked or not. – Evan Cordell Dec 26 '11 at 03:30
  • No such property as `clearsSelectedOnViewWillAppear` in `UITableViewController`. Did you mean `clearsSelectionOnViewWillAppear`? – Pang Nov 09 '13 at 10:11
11

Make sure you are calling the super implementations of the viewWill... and viewDid... methods

John Estropia
  • 17,460
  • 4
  • 46
  • 50
  • I'm doing that in every inherited method. – Evan Cordell Dec 27 '11 at 04:19
  • How are you returning to your UITableViewController? Are you using the default back button that comes free when you use a `push` segue in the storyboard? – John Estropia Dec 27 '11 at 04:34
  • I am. My UITableViewController is inside a UINavigationController, and I return to the tableview from the detail view with the back button the navigation controller creates. (and the segue is a ``push`` type) – Evan Cordell Dec 27 '11 at 04:49
  • I'm doing the same way as how you describe but never had an issue like this. It's hard to say without knowing your controllers' behaviors but I'm throwing around some ideas. Are you sure it's the same view controller instance that you are popping to? You can test this by doing a `NSLog(@"%@", self);` on your UITableViewController's `viewDidAppear:` and `viewDidDisappear:`. – John Estropia Dec 27 '11 at 06:27
  • It's the same controller instance. – Evan Cordell Dec 30 '11 at 22:09
11

Not sure about the use of segues but I often want to refresh data when a view controller appears. If you reload the table however, you clear the select row. Here is some code I use to maintain a selected row and show the deselect animation when returning. It may be the case that this may help you so I will post it here.

-(void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];

    NSIndexPath *indexPath = [tableView indexPathForSelectedRow];
    [tableView reloadData];
    if(indexPath) {
        [tableView selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionNone];
    }
}

-(void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];

    NSIndexPath *indexPath = [tableView indexPathForSelectedRow];
    if(indexPath) {
        [tableView deselectRowAtIndexPath:indexPath animated:YES];  
    }
}
Chase
  • 11,161
  • 8
  • 42
  • 39
  • I do reload the table data, but your solution didn't work. (I had tried it before, but to be sure I tried again.) – Evan Cordell Dec 30 '11 at 22:03
  • Are you reloading the table somewhere else? Also be sure that you are not removing the selected row prior to calling viewWillAppear. Depending on how your data changes, reselecting the same row may not work for you. – Chase Dec 31 '11 at 15:03
  • I accepted this even though I never solved this problem. I suppose I must be reloading somewhere. – Evan Cordell Jun 25 '12 at 00:00
5

For Swift 3

override func viewWillAppear(_ animated: Bool) {

    super.viewWillAppear(animated)
    if let path = tableView.indexPathForSelectedRow {

        tableView.deselectRow(at: path, animated: true)
    }
}
1

Swift Update :-

override func viewDidAppear(animated: Bool) {
    super.viewDidAppear(true)
    if tableView.indexPathForSelectedRow != nil {
        let indexPath: NSIndexPath = tableView.indexPathForSelectedRow!
        tableView.deselectRowAtIndexPath(indexPath, animated: true)
    }
}
Mudith Chathuranga Silva
  • 7,253
  • 2
  • 50
  • 58
1

Better Swift update:

 override func viewWillAppear(animated: Bool) {
    super.viewWillAppear(animated)

    if let path = tableView.indexPathForSelectedRow {

        tableView.deselectRowAtIndexPath(path, animated: true)
    }
}
Tuslareb
  • 1,200
  • 14
  • 21