7

I've been stumped by this for a while...

When you tap the cell of a contact in Apple's Phone app for the iPhone (entering the view with contact details) and tap back to the previous view, there is a brief animation (fading from blue to white) showing the deselection of the cell. This is the behavior with all table views in Apple's own apps, and also the recommended behavior according to their Human Interface Guidelines.

However, in my own project I've been having trouble replicating this behavior. None of the cells in my UITableView are selected when I return to it from a detail view.

I looked through the CoreDataBooks sample code in Apple's documentation, which has the desired cell deselection behavior, and it seems like the table view gets the behavior "automatically" (without any specific implementation).

I've also tried implementing the solutions in these very similar questions:

What deselect selected cell when navigationController pops a view?

iPhone UITableView cells stay selected

UITableView doesn't keep row selected upon return

But I always get the same result -- none of the cells in the UITableView are selected when I return to it. (Even after adding [tableView deselectRowAtIndexPath:[tableView indexPathForSelectedRow] animated:animated]; in the view controller's -viewWillAppear: method.)

It was also suggested in the comments of one question that having [[self tableView] reloadData]; in -viewWillAppear: may be causing the cells not to stay selected. But CoreDataBooks does the same thing and still has the desired behavior (seemingly) without any specific code.

Any suggestions on how to resolve the problem? Thanks in advance.

On a side note, I don't quite understand why the code to deselect the cell should be implemented in -viewWillAppear: (rather than -viewDidAppear:). Wouldn't that cause everything to happen before the table view is displayed on screen? This is probably just due to lack of proper understanding of a view's life cycle on my part, but any clarifications would be nice. Thanks again.

Community
  • 1
  • 1
James
  • 762
  • 8
  • 22
  • Just in case it matters, I'm using Xcode 4.2 and the iPhone 5.0 Simulator. My project uses ARC. – James Jan 11 '12 at 17:26
  • While calling deselction method from viewWillAppear, have you debugged value of indexpath?What is present in that time? – rishi Jan 11 '12 at 17:40
  • 1
    Not sure if I did this correctly, but I tried logging the returned value for `indexPathForSelectedRow` and the section and row were both "(null)". – James Jan 11 '12 at 18:00
  • That is main issue, you are not keeping the value of indexes of cells those you want to be selected. You need to store those also, then need to call this method. – rishi Jan 11 '12 at 18:07
  • Thanks. Could you be a bit more specific on how to do this? (I'm still a beginner working on my first project.) Also, as mentioned, the CoreDataBooks sample code seems to have the desired behavior without any specific implementation. Is there a simpler way to do this? Or am I just not looking in the right places? – James Jan 11 '12 at 18:19
  • At the time of cell selection you can keep an array of indexpath, now once you return to previous view you can pass them then, am i clear now? – rishi Jan 11 '12 at 18:26
  • Actually, I've realized that the indexpath values are "(null)" even after replicating the desired cell deselection behavior (but without updated table view data; see comments in Walter's answer). So I guess I'm not logging the values properly. So far, `reloadData` (which I need so newly added cells will be displayed) seems to be causing the problem (again, see Walter's answer and comments). – James Jan 12 '12 at 02:26
  • reload data will not cause the issue, what you are supposed to do is to track the selected rows and store them, so that on returning to same view you can use those. – rishi Jan 12 '12 at 14:30
  • Would it be possible for you to show me where this is done in the CoreDataBooks sample? I'm just starting out with coding and it would be much easier if I had something specific. Thanks in advance. – James Jan 12 '12 at 15:24
  • is is possible for you to send me your code, if that is not secret then i will update and send you. – rishi Jan 12 '12 at 15:26
  • Sure, I will have to edit it a bit first though. Where should I send it to? Thanks again. – James Jan 12 '12 at 15:33
  • my email id is their in my profile. – rishi Jan 12 '12 at 15:35
  • Your email isn't visible in your profile to me for some reason. – James Jan 12 '12 at 16:29
  • No need do do work.. I will post one similar example out here. so that it will be easy for you to check and understand. – rishi Jan 12 '12 at 16:34
  • Thanks a lot! (I already edited the project, and could send it to you if it's easier.) – James Jan 12 '12 at 16:40
  • I think now you got the answer, so you can close this question. – rishi Jan 15 '12 at 09:08
  • 2
    I mentioned in my email, that it's not really an answer to the question but a workaround. I was actually still hoping that someone might be able to provide a real answer (why CoreDataBooks has everything working seemingly without specific implementation, for instance). – James Jan 15 '12 at 10:02

2 Answers2

2

Have you experimented with the clearsSelectionOnViewWillAppear property of a UITableViewController (not just a tableview but a tableviewcontroller)? If you set it to NO it will make the selection stay blue.
To get your desired effect,you will also probably need to add a call to
- (void)deselectRowAtIndexPath:(NSIndexPath *)indexPath animated:(BOOL)animated
to ensure that it doesn't stay blue forever.

Look in the Overview section of the UITableView Documentation to get started.

//EDIT// As noted in the comments below, what we finally ended up doing is moving the call to [[self tableview] reloadData]; to viewDidAppear.
My guess is that CoreDataBooks has a complex enough table (with sections and books and sections and books) that something is going on with the timing of events.

Walter
  • 5,867
  • 2
  • 30
  • 43
  • Originally, in `-viewWillAppear:` I only had `[super viewWillAppear:animated];` and `[[self tableView] reloadData];`. I played around with adding `[self setClearsSelectionOnViewWillAppear:NO];` and removing `[[self tableView] reloadData];`. Seems like the problem is that `reloadData` is clearing cell selection before the table view is displayed. When I remove it, cell deselection seems to behave as desired, however I need `reloadData` so that newly added cells will be displayed (upon dismissing the modal view controller adding them). – James Jan 12 '12 at 02:08
  • Setting `clearsSelectionOnViewWillAppear` to `NO` only makes a visible difference when `reloadData` is removed as well (the previously selected cell is, predictably, stuck in highlighted state) and hence, unrelated to the problem at hand. – James Jan 12 '12 at 02:15
  • It would be pretty hacky but you could call the `reloadData` with a delay. Something like `[[self tableView] performSelector:@selector(reloadData) withObject:nil afterDelay:0.2];`. I don't know if it will work though. – Walter Jan 12 '12 at 10:28
  • I'd prefer not to do something hacky, but in this case I don't even think it would give me the desired result. Upon returning to the view I'd like the newly added cell to already be there, if possible I'd like to show the deselect animation for the cell as well. At the very least, I'd like the deselect animation to show when just navigating between views but not adding cells. What puzzles me is that CoreDataBooks also calls `reloadData` in `-viewWillAppear:` but works fine. – James Jan 12 '12 at 12:39
  • I've been playing with this today. In the simulator if I put the `reloadData` in the `viewDidAppear` I can get a stock navigation project to act like coredatabooks. If I put it into `viewWillAppear` I can get it to match what you are seeing. So...my guess at this point is that the only reason it works in books is that they have lots of sections and lots of entries. But that's just a guess. – Walter Jan 13 '12 at 16:45
  • I tried it and it works like you say. Calling `reloadData` in `-viewDidAppear:` causes the new cell to be added after a brief delay, however. Otherwise it would suffice as a workaround. Thank you for the answer. – James Jan 14 '12 at 12:15
  • Glad I could help. If this is an acceptable answer, please don't forget to mark it as such. I have updated the answer itself to reflect what we finally decided to do. – Walter Jan 15 '12 at 17:49
  • Because this answer is not marked as accepted, I set out to answer it, and found your edit of moving reloadData to did appear does work as expected. I would like to suggest setting `self.tableView.userInteractionEnabled = NO;` in `viewWillAppear:` then in `viewDidAppear:` after `reloadData` set `userInteractionEnabled` back to YES. This will prevent a crash if the user manages to select a row before you have refreshed the table view. Not likely, just for safety. – NJones Jan 15 '12 at 19:17
  • Hi guys, thank you for replying. The reason I haven't accepted the answer is because the result is only close to but *not* the behavior I'm trying to achieve. Moving `reloadData` to `viewDidAppear:` fixes the deselect animation problem, but it causes a newly added cell to appear *after* the table view is shown to the user. I feel that for a workaround suffice, the user should at least not be able to notice the difference. In this case, the user is able to observe that the cells appear after the table view is presented (expectedly so, since we call `reloadData` in `viewDidAppear:`). – James Jan 16 '12 at 07:52
  • (...continued from previous comment) However, this isn't the standard behavior when adding items to a table view on the iPhone. Try adding a contact to your Favorites in Apple's own Phone app. The new contact is just *there* when the view is presented. Also, as I've mentioned, the CoreDataBooks sample code calls `reloadData` in `viewWillAppear:` and works fine, so I think an answer that addresses this would also benefit those who (for some other reason) needed to call `reloadData` there instead of `viewDidAppear:`. – James Jan 16 '12 at 07:54
  • (Please correct me if I'm wrong and a newly added contact in your Favorites does appear after the table view is shown to the user and is just blocked by the modal view's animation. Thanks.) – James Jan 16 '12 at 07:54
  • I'm afraid this is beyond me at this point. I've spent another 2 hours today but I cannot figure out what is special about CoreDataBooks. I created a fresh project and tried to match CDB as best as I could but no luck (CDB is an old project with old settings). When I look at Favorites (I assume you mean in the Phone app) it does not display the deselect animation like CoreDataBooks does. – Walter Jan 16 '12 at 15:27
  • Yes, Favorites doesn't display the deselect animation when adding a new contact. Neither does CoreDataBooks when adding a new book. I merely used Favorites to illustrate why I need to call `reloadData` in `viewWillAppear:` and why calling it in `viewDidAppear:` would be changing the user experience, if only very slightly, to avoid the problem rather than fixing it. Regardless, thank you for trying to help! (Sorry for the late reply. I got the notification of a new comment, but couldn't see the comment until now.) – James Jan 17 '12 at 08:00
1

If you want to deselect a cell, use the - (void)deselectRowAtIndexPath:(NSIndexPath *)indexPath animated:(BOOL)animated and use [self.tableView deselectRowAtIndexPath:indexPath animated:YES]; or [tableView deselectRowAtIndexPath:indexPath animated:YES];.

Souljacker
  • 774
  • 1
  • 13
  • 35
  • Please read the question and comments. The answer you suggested is already part of the question. Thanks for trying to help regardless. – James Jan 12 '12 at 16:31
  • the reason why I answered like this, is because if you change the `tableView` to `self.tableView` it works sometimes. – Souljacker Jan 12 '12 at 16:58