I use a UITableView to display a list of items, and when a row is selected I show that item in a detail view next to it (using a split view controller).
As the selection in the table view changes I want my detail view to change as well, which is of course standard behavior and it works flawlessly... except when no row is selected anymore in the table view.
Users can for example delete a row from the table view, and during and also after that deletion there will be no selected row in the table view. Of course after a row is deleted I let my detail view controller know, but during the editing process in the table view, when no row is selected, my detail view controller does not know this.
I tried to use the UITableViewSelectionDidChangeNotification but that only gets sent when the user selects a different row, not when a deselection occurs.
How can I be notified of the fact that the table view switches from having a row selected to having no selection at all?
EDIT:
As a temporary solution, I tried renaming the Edit-button to "Reorder" and only allowing moving rows from A to B but without allowing the deletion controls, but this can not be done, there is no move control without enabling editing on a row. The thing is, I do get a pointer to a row that is up for moving, so I can keep that selected. I do not get this pointer for a row up for deletion, so no go for me. I always want to know what row a user works on, and keep that row selected at all times.
I may have to resort to ditching the standard editing behavior and adding my own buttons and methods for it. Or see what gestures can do for me to capture touches on any row...
There is a property indexPathForSelectedRow. I'm not sure what it would return when there is no selected row, but it may return nil or something like that, which you could use as a trigger to know if there are any rows selected. Something like
if (myTable.indexPathForSelectedRow == nil)
{
//do something here to account for no rows being selected
}
else
{
//do stuff here to set up your detail view
}
Let me know if this works for you.
How are you implementing the deletion of rows? Are you implementing the following data source method?
tableView:commitEditingStyle:forRowAtIndexPath:
You can have a property like
NSIndexPath *selectedIndexPath
and set it to nil when a row is being deleted.
Example:
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
//select another row in your table
[tableView selectRowAtIndexPath:*indexPathOfTheRowToBeSelected* animated:YES scrollPosition:UITableViewScrollPositionNone];
//then delete row from data source
}
The method above will be called when the user touches the delete button on the table he/she has selected to delete.
Okay I misread what you were asking at first, I'm pretty sure what you want is either – tableView:willDeselectRowAtIndexPath: or – tableView:didDeselectRowAtIndexPath:. These methods will be triggered automatically when the user deselects a row (either right before the row is deselected or right after, respectively). Implement one of these in your table view delegates code, and you'll know whenever a row gets deselected, and you can put your code to select the next row or whatever you want in one of these methods.
I struggled with this as well. Turns out that when the "Edit" button is hit, all rows are deselected at that point. You can override setEditing:animated: to detect when it is hit, but you must call [super setEditing:editing animated:animated] before you return.
See this link for where I found this:
How can i identify self.editButtonItem button's clicked event?
Related
The setup: The table has 1 custom cell. This cell has 1 text box. In each text box a number is entered. The tableView has 5 rows (of this cell). If I change one number in any of the cells, then all the cells need to be updated, I simply call tableView.reloadData(). The change in the text box is handled with the editingDidEnd event.
The problem: I click any of the textFields and change the number. Then, I click another textField to change its value. first editingDidEnd is called, all the values are re-calculated, and tableView.reloadData is called. Now, the click to the second textField is missed because the table is reloaded.
I am not able to update the cells directly because they are custom cells and the value is changed within that class. I cannot update ALL the cells from custom cell class.
A difficult question to explain in writing especially for a non native English speaker. If you understand the question, any pointers will be appreciated :).
Using Xcode 7.1 and Swift. Thank you.
When you call reloadData, all the cells are removed from the tableview and re-added. Since it is removed, it is no longer in the responder chain meaning its text field can't be the firstResponder (selected).
There are two options that could work.
Keep track of the row that is selected, call reloadData then call becomeFirstResponder on the text field for the correct row.
Not call reload data and just update the values in the text fields. This option more depends on the striation of your app.
This can be quite simple, ideally you are in a position to store the values for the field you want to focus and the index path of the cell in question (such as when you regenerate the editing field after your reload?)
This code should help:
- (void)tableView:(UITableView *)tableView
willDisplayCell:(UITableViewCell *)cell
forRowAtIndexPath:(NSIndexPath *)indexPath
{
if(indexPath == self.editingIndexPath)
{
[self.editingTextField becomeFirstResponder];
}
}
i have a tableview with form fields, and there is a row that use segue to call an UICollectionView, everything is works except that i can't keep the selected cells (the visual effect that i show when the cell is selected) after go back to the tableview.
I mean, i selected my UICollectionView cells, after that i go back to the form, but if i need to again to my UICollectionView Cells, to deselect o select more cells before submit the data, once the UICollectionView appear my previous selection are there (i print the array, and i see the values) but i cant see the effect that i did for selected cells.
How i can keep the effect for selected cells if I'm going back to select again o deselect cells?
One thing to realize is that this is not going to happen by itself. When you segue back to the table view and the form fields, the UICollectionView is completely destroyed. The next time you show the collection view, it is a new and different collection view.
So, if you want to maintain a knowledge of what the selection was in the collection view, you are going to have to maintain it yourself, deliberately, storing it somewhere when you know that the collection view is being destroyed.
That way, the next time you show your collection view, even though that will be a completely new and different collection view, you can pass the knowledge of what the selection was to that collection view as you create and show it. The user will have the illusion of "returning" to the collection view, in the same state, but in fact you will have saved and restored its state.
It is then just a matter of reflecting the selected state in the collection view's display of its items. To do that, you need to configure your model so that when cellForItemAtIndexPath: is called, each cell looks selected if that item is supposed to be selected.
Every time you use segue to call an UICollectionView a new instance of UICollectionView is created and hence states of selected cells doesn't get restored.
I believe u must have taken an array of index paths of selected indexes to show the visual changes in the cell.
Make your tableView class as delegate of UICollectionView. Using its delegate methods return the selected index array to tableView class .And before pushing to UICollectionView send the same array of index paths back to the UICollectionView. Hope it helps.. Happy Coding.. :)
I'm using Xcode 5.1 with iOS7. In my app I have a static uitableview made up of several sections, each has 2-3 rows. I used a static table because this my settings view controller and the contents will not change.
In one such section I have 2 rows. Each row has a label on the right side, similar to the iPhone's General --> Auto-Lock rows.
Like the auto-lock row, when the user selects the row it segues to another tableview controller made up of several rows. Whenever a user selects a row here, I show a checkmark. When the user backs out of this vc I show the name of their selection in the label on the right-side of the row, again just like the auto-lock example.
I use an unwind segue to pass the selected value back (from detail to master, you could say) so I know what the user selected and that's how I set the value in the label that's sitting on the row.
What I'd like to do is be able to already have the detail tableview row checked with the last value the user selected (again, like the auto-lock example). I know the name of what they selected because I send it over in the prepareForSegue. I don't know how to tell the tableview which row to put the checkmark because the detail table doesn't have any connection to the master table, sending 'indexPath.row' wouldn't work. Because I have a small amount of rows, I could just check each row and see if its text is equal to the text that I sent over. I'm not sure if that's the best way to do it, though, because I'd like to allow the user to enter their own text in these labels in a future release. I'd appreciate any ideas. Thanks!
EDIT: I should better clarify my issue and what help I'm looking for. I have 2 rows in a Settings table that both segue to a detail table. This detail table contains several rows of static data. At the time the user selects a row from this detail table, I don't know which row from the Settings table is making the request; I just hand back the label on the row thru an unwind segue. Because of this, I need to be able to look up the value of the data (sent from the Settings table) on the 'viewDidLoad' of the detail table. I'm sorry for not making this clearer from the beginning.
I would simply record the row (or also section, if you want) under a NSUserDefaults key. In viewDidAppear you can set the checkmark.
This would work in any event. If you allow editing and, say, deletion of a row, you can adjust this setting on the fly. Equally, changing the text of the label would be irrelevant.
- (void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
...
if (indexPath.section == kTrackedSection) {
NSInteger selectedRow = [[NSUserDefaults standardUserDefaults] integerForKey:kSetting];
if (selectedRow == indexPath.row) { return; }
UITableViewCell *otherCell = [tableView cellForRowAtIndexPath:indexPath];
otherCell.accessoryType = UITableViewCellAccessoryNone;
[[NSUserDefaults standardUserDefaults] setInteger:indexPath.row ForKey:kSetting];
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
}
I have a UI table view loading data from network. If the user move the finger on one cell, one button will be displayed, just like iPhone style delete button. If the user click this button, the value of one label in the cell will be changed accordingly. However, I didn't find any way to make table view to re-draw this cell, except for reload the whole table. I don't want to use reload data method, because I just need change the value in one cell instead of the whole table. Any suggestion on this?
Take a look at the method
- (void)reloadRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation
Calling this method will result in your table view's data source asking its delegate for information about that cell.
For future reference, I found this very easily by checking the documentation on UITableView. I suggest you do that in the future before posting here.
Essentially I have a list of items, I want to have some type of checkbox on the end where they can select multiple items. I also need them to be able to just select one of the rows and have it open up a detail view. Is this possible? Or do I need to do something like they do with the messages where you choose the edit button to select them and show an additional button to take action on the selected?
Set your cell's UITableViewAccessoryType property to UITableViewCellAccessoryCheckmark to make a check mark show up on a certain cell, you'll have to keep track of which cell's are checked on your own though, since this property doesn't track.
So have an array or something that represents which cells ar checked and which aren't, then in your didSelectRowAtIndexPath: method you can modify the data in the array to reflect the cell's selected state, and call [tableView reloadData] so the checkmark shows up right away.
I found the answer, there's an option to allow multiple selections on edit mode.