iOS: Put checkmark on preselected row on viewDidLoad - ios

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

Related

How to update a UITableView so that UITextField in a cell won't lose focus

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

One click, multiple actions Custom Cell of TableView

What I do
I have a created a custom cell which has a button with a specific image on it. Now depending on some conditions I set that image image1.jpg or image2.jpg.
How I do that
The custom cell is created by creating a protocol where I click that buttons action, I notice in the main interface, that the button is pressed and I pass as a parameter the button instance.
Issue
Now, the problem is when I click that button in a specific cell, I change cell.button's image, but also with that, when I scroll down, I see that there are other cells that have changed their image.
Any idea why is this happening?
Due to the reuse of cells by the UITableView, when the cell moves out of the screen, it is moved to a queue and then reused when there are new cells to load.
If you want to keep each cell's property unique, you will have to reconstruct its values every time. For that you can keep some kind of data array that stores the state/condition of each cell. The array will be ordered by the indexPath of the tableView, and then you can just fetch the state from the array based on the indexPath and update the cell to be the right image.
What is happening is that when you change the image of your cell and later scroll down or up, your cell is being reused to present another information.
To fix that you should check your UITableView data source, see if you're reusing cells in this method:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
I'd recommend to configure the cell before returning it in the previous method, and assign the appropiate image for the button at that time. To achieve that you'd need some mechanism for remembering the state of each cell.
For more information about cell reusing and cell in general you could go to the Apple Docs for UITableViewCell
As described in above answer you can manage button selected and unselected state in array for that you can even add one key in the array that you are using for the data to display.
and on didselect event of table you can change the key of selected field like this
NSMutableDictionary *newDict = [[NSMutableDictionary alloc] init];
NSDictionary *oldDict = self.dict_trans_Details ;
[newDict addEntriesFromDictionary:oldDict];
[newDict setObject:status forKey:#"transactionstatusid"];
[table_transdetails_array replaceObjectAtIndex:self.indexValue withObject:newDict];
Thanks.

UITableView deleteRowsAtIndexPaths not working

I'm not quite sure what's going on here but I'm running into a contact form that I'm working with. In my form I've added the ability to add an email address to a contact. As pictured below, once the user clicks on "add email", a row is added to the "Emails" section.
However after I click to delete the email, an extra cell appears underneath the add email button (pictured below).
There's a little red box from what appears to be the prior delete cell as though the table isn't reloaded. Here's my delete code:
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if( editingStyle == UITableViewCellEditingStyleDelete )
{
// Update the data source
NSMutableArray *fields = (NSMutableArray *)self.fields[#(indexPath.section)];
[fields removeObjectAtIndex:indexPath.row];
NSMutableArray *values = (NSMutableArray *)self.values[#([self fieldTypeAtIndexPath:indexPath])];
[values removeObjectAtIndex:indexPath.row];
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationMiddle];
}
}
So why is that cell remaining afterwards? I can call [tableView reloadData] within the method above and it removes the excess cell but then it messes up the animation. Can you shed some clarity on what I'm doing wrong here?
This looks like a bug.
I just noticed that even Apple has this same bug in their Reminders app. It seems to be related to deleting rows from a UITableView with variable height items.
In Apple's Reminders app, when you delete something from a long list with variable height items, you will see the same exact visual artifact for a split second. Then the table jumps and the list looks correct. I am assuming Apple just reloads the entire table view a second after the item is removed in order to fix the visual glitch.
My recommendation is to report this as a bug to Apple. For now you can reload the entire table view like Apple presumably does.
Option 1: Before you call deleteRowsAtIndexPaths, you must make sure that numberOfRowsInSection will return the correct value (e.g. if you originally had 2 rows in that section, it should now return 1 row).
Option 2: If that isn't the problem, I would try a different animation type (e.g. UITableViewRowAnimationAutomatic), just to see if that has any effect.
Option 3: Ensure that cellForRowAtIndexPath is returning a valid cell with its contents being reset. Otherwise it may be reusing an invalid cell or displaying something that was there before.
Option 4: Since the heights are different, ensure that heightForRowAtIndexPath is returning the correct value. You probably need to call reloadRowsAtIndexPaths in order for the table view to know about the height difference.
I had the same problem and I guess it might be a bug in iOS7 where it doesn't repaint the cells correctly, I fixed it but not in an efficient way, just in the "cellForRowAtIndexPath" , always create a new cell, don't dequeue it.

How to know that no row is selected in my UITableView?

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?

Changing UITableView functionality on button press

I'm trying to figure out the best way to do this - I have a UITableView of items which the user has previously selected and which is stored. When you click an item it takes you to a detail page. What I need is to be able to click a button below the table view which reloads the table and changes the accessory so its a tick instead of a disclosure, then the user can un-tick the items and remove them from the list, before clicking another button which reloads the updated table and restores the disclosure accessory.
Question is, what is the best way to "remember" which way to handle the table reload after the click so it knows which way to display it? Would you use the NSUserDefaults to store a flag on the button click or is there a more elegant way to do it? I guess I could use the status of the button, whether it's in one state or another, but I'm guessing there is something in-built I'm missing.
Hope that makes sense - thanks.
Usually I have some 'model object' and depending on array of those objects I construct table. My cellForRowAtIndexPath looks like this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
InterestsCell *cell = (InterestsCell*)[tableView dequeueReusableCellWithIdentifier:kInterestsCellID];
if (cell == nil) {
...
}
Interest *i = (Interest*)[self.interestsArray objectAtIndex:indexPath.row];
cell.myTfSubview.enabled = i.isChecked;
return cell;
}
If you don't have your model then you can create array of BOOL values and store flags there.

Resources