I'm writing an iPhone application with a tableview which displays a list of items,each one with a checkmark. I can selected/deselect each item just with one click. When I press a button [DONE] I would like to iterate along all the cells and check which one has the checkmark enabled. Something like:
for (int i = 0; i < [fullDataset count]; i++) {
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:i inSection:0];
UITableViewCell* cell = [self.tableView cellForRowAtIndexPath:indexPath];
if (cell.accessoryType == UITableViewCellAccessoryCheckmark) {
NSLog(#"THIS CELL IS SELECTED!");
}
}
Now,the problem is that using this procedure I get only the cell which are selected and which are CURRENTLY DISPLAYED. I want to be sure that the procedure runs across ALL the cell,even the ones not displayed. I might use another data structure for keeping track of the selection but it looks to be a bit redundant.
Any idea?
Thanks a lot!
Claus
You can't count on the cells to tell u if selected or not, cells get reused and always change there state.
You need to manage a separate NSSet of the selected indexPaths, when user tap on a cell, u add this indexPath to the set, when he deselect the cell u delete the indexPath from the set.
Related
I have a UITableView with prototype cells that have a UISwitch on them. When the user taps the switch on any particular cell, I need to determine which object in my datasource has had its switch toggled.
Here is my method for the switch:
- (IBAction)completeSwitchTapped:(id)sender {
UITableViewCell *cell = (UITableViewCell *)[sender superview];
NSIndexPath *indexPath = [self.itineraryTableView indexPathForCell:cell];
NSLog(#"cell row is: %d in section: %d", indexPath.row, indexPath.section);
}
But this always returns row 0 in section 0 regardless of which row or section was picked.
How do I properly return the correct cell which contains the switch? Clearly [sender superview] isn't working and I'm considerably at a loss for how to reference the cell.
Thanks!
Try something like this:
UIView *superview = sender.superview;
while (![superview isKindOfClass:[UITableViewCell class]] && superview.superview != nil) {
superview = superview.superview;
}
NSIndexPath *indexPath = [self.itineraryTableView indexPathForCell:superview];
When creating the button/switch, set it's tag to the cell row or some other meaningful value. Then simply extract sender.tag when the IBAction method is invoked, to retrieve the cell row.
When I have to do buttons and switches like this in my own tables, I usually subclass UIButton or UISwitch and in my subclass, I add a ".indexPath" or ".row" property to my subclassed control.
Which I set when I return the freshly populated (or reset) table view cell in "cellForRowInIndexPath:"
That way, when your switch or button is touched, you'll have a property that has the correctly set row index ready for you to work with.
A much more straightforward & less janky solution versus doing "superview.superview".
I have a UITextView populated with data from a UITableView (tvServices); when the user taps on a row in the UITableView, I move the contents of that cell to the UITextView, after which the contents of the UITextView are stored in a CoreData store.
When the user selects a record for updating, I move the contents of the stored UITextView back into the UITextView. When the user taps on the UITextView, I display the entire UITableView as a UIPopover, with the contents of the UITextView marked with a checkmark (AccessoryCheck) in the UITableView.
Unfortunately, this is not working the way I designed it... nothing gets checked. Here is my code ( this is a proof of concept - where I check every row in the UITableView to make sure it can be done). globalServicesArray is the data source for the UITableView cells:
for (int i = 0; i < sharedServicesArray.globalServicesArray.count; i++) {
NSIndexPath *path = [NSIndexPath indexPathForRow:i inSection:0];
UITableViewCell *cell = [tvServices cellForRowAtIndexPath:path];
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
I hope this makes sense; if there is a better way of doing this, I'm open for suggestions... otherwise what am I doing wrong?
Assuming only one cell can be edited, can you try this. Store the index path in a class level iVar/Property, say. selectedIndex and reload the cell
//To hold the index paths
NSMutableArray *reloadArray = [NSMutableArray array];
if (self.selectedIndex)
{
//if already selected deselect
[reloadArray addObject:self.selectedIndex];
}
for (int i = 0; i < sharedServicesArray.globalServicesArray.count; i++) {
NSIndexPath *path = [NSIndexPath indexPathForRow:i inSection:0];
[reloadArray addObject:path];
}
[tvServices reloadRowsAtIndexPaths:reloadArray withRowAnimation:UITableViewRowAnimationNone];
In cell for row at index path check for the index path and set accessory checked if matches the index
if (self.selectedIndex &&
self.selectedIndex.row == indexPath.row &&
self.selectedIndex.section == indexPath.section)
{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else
{
cell.accessoryType = UITableViewCellAccessoryNone;
}
I'm creating an app which contains a screen that shows a table view with custom cells. Each cell contains two labels and a subview, which further contains other subviews. I'm handling the click event on the cell to hide/show the subviews within the subview in the cell. How can I make it so that when I click on a single cell, the subview of all the cells will change?
It is like the Stock application in iPhone (using iOS 7), here is a screenshot:
As in the image above, when you click on any of the green box, all the boxes change to reflect the same type of value.
Please let me know if this approach is fine, or how this can be implemented.
There are a couple ways of doing this. The first that comes to mind would be to handle the different states within the UITableViewCell subclass, and just reload the visible cells:
[self.tableView reloadRowsAtIndexPaths:[self.tableView indexPathsForVisibleRows] withRowAnimation:UITableViewRowAnimationAutomatic];
If you're looking for more control over the process though, this process could also be achieved by changing the state future cells should load into, and then calling a method on every visible cell. This would provide you with an easy way to have complete control over how the contents of the cell update.
// Change flag for cell state then...
for (NSIndexPath *indexPath in [self.tableView indexPathsForVisibleRows]) {
if (condition) {
MyCellSubclass *cell = (MyCellSubclass *)[self.tableView cellForRowAtIndexPath:indexPath];
[cell someMethodWithArg:(id)state];
}
}
To do something as in Stock app you should handle two method cellForRowAtIndexPath: and click action method.
In cellForRowAtIndexPath: you should do the check which cell/button was pressed and display value base on it:
//Pseudo code
//cellForRowAtIndexPath
if (cellNo3Pressed)
{
//set up text with the right value.
}
else if (otherCell)
{
//set up text with the right value.
}
This will handle the cell which are not visible on the screen.
The next action method should handle nice animation on all of the visible cell:
NSArray *paths = [tableView indexPathsForVisibleRows];
for (NSIndexPath *path in paths)
{
UITableViewCell *cell = (UITableViewCell *)[self.tableView cellForRowAtIndexPath:path];
//Animate changes for cell
}
I have a tableView who's datasource is an array with 400 static items in it. In my app you can select a row and it will place a checkmark on that row. I'm keeping track of the checked item's indexPaths in another array so that the table can be reloaded later and those items will still be checked.
Since my table has a lot of values in it I've added a searchDisplayController. Start typing what your looking for and it'll filter the list down to those items. You can select rows in the searchResultsTableView and it will check them, just like in the main table with the 400 static rows. However, there's a problem:
Let's say you enter a search and narrow the list of 400 items down to the one you're looking for and you select (checkmark) it. In the full list of 400 items, the one you just searched for might be number 112 in the list, however when you did your search and filtered down to only that one item, instead of adding the indexPath of item 112 to my array that keeps track, it entered the indexPath of item 0 because it was the only item showing in the filtered list.
So when you cancel out of search and go back to the main list instead of their being a checkmark on item 112, there's a checkmark on item 0.
So I'm looking for a way to keep my filtered array in sync with my main tableView datasource.
The relevant bit of my didSelectRowAtIndexPath method:
if (tableView == self.searchDisplayController.searchResultsTableView) {
cell.textLabel.text = [filteredattributesArray objectAtIndex:[indexPath row]];
if(cell.accessoryType == UITableViewCellAccessoryNone){
cell.accessoryType = UITableViewCellAccessoryCheckmark;
[selectedItemRows addObject:indexPath]; //Add the index path of checked cell into array to keep track
[tableView reloadData];
} else {
if(cell.accessoryType == UITableViewCellAccessoryCheckmark) {
cell.accessoryType = UITableViewCellAccessoryNone;
[selectedItemRows removeObject:indexPath]; //Remove that index path of unchecked cell from index array
[tableView reloadData];
}
}
[tableView deselectRowAtIndexPath:indexPath animated:YES]; }
}
Don't use indexPath. Set the tag value on each item in your data array and then keep a list of tags for your "checkedArray". That way you can evaluate the checked items independent of the cells or tableView structure.
I have created a five column (text boxes) cell (row) in table view controller with an option of add button. When a user clicks on add button, a new row (cell) with five column (text boxe) is added in a table view controller with null values. I want that when user fills the text boxes the data should get saved in database or if he changes any data in previous text boxes also it get saved.
this is my save btn coding..
- (IBAction)btn_save:(id)sender
{
NSInteger noOfRow=[(NSSet *)[projectObject valueForKey:#"rs_project_Input"] count];
NSLog(#"Save Btn: No of rows for saving %d",noOfRow);
for (row1=0; row1<noOfRow; row1++)
{
NSLog(#"Row is %d",row1);
path = [NSIndexPath indexPathForRow:row1 inSection:0];
Input_Details *inputDetailsObject1=[[self sortInputs] objectAtIndex:path.row];
/*
Update the input details from the values in the text fields.
*/
EditingTableViewCell *cell;
cell = (EditingTableViewCell *)[self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:row1 inSection:0]];
inputDetailsObject1.mh_Up= cell.cell_MH_up.text;
inputDetailsObject1.mh_down=cell.textField.text;
NSLog(#"Saving the MH_up value %# is saved in save at index path %d",inputDetailsObject1.mh_Up,row1);
[masterController saveContext];
}
[self.tableView reloadData];
}
My problem is that the code is not helping in saving the data. Plz help.
Thanks
You try to use the table view cells as a data source, which will not work (apart from being a bad design). The problem is that
[self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:row1 inSection:0]]
returns nil if the cell at that row is currently not visible. (A table view allocates only cells for the visible rows and reuses these cells as you scroll up or down.)
You have to track changes to the text fields immediately, e.g. by implementing a textFieldDidEndEditing: delegate function, and store the changed text in your data source.