How to track the index of all seleted cells in UITableView - iphone

I have a UITableView with about 20 rows. I also use check mark accessory to identify the selected. The problem I face now is that the selection gets messed up when I scroll (here I am selecting multiple rows). So after scroll the selected checkmark has vanished. Can anyone help me to find a way? in didSelectRowAtIndexPath:
NSMutableDictionary *rowDict = [tableList objectAtIndex:[indexPath row]];
if([tableView cellForRowAtIndexPath:indexPath].accessoryType == UITableViewCellAccessoryCheckmark)
{
[tableView cellForRowAtIndexPath:indexPath].accessoryType = UITableViewCellAccessoryNone;
}
else
{
[tableView cellForRowAtIndexPath:indexPath].accessoryType = UITableViewCellAccessoryCheckmark;
checkedIndexPath = indexPath;
NSLog(#"the checked psths are :%#",checkedIndexPath);
}
And in cellforrowatIndexpath I use
if([self.checkedIndexPath isEqual:indexPath])
{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else
{
cell.accessoryType = UITableViewCellAccessoryNone;
}
But this works only for single selection. What should I do for multiple selection?

You can have an NSMutableArray which can add n number of NSIndexPaths corresponding to the cells selected. When a cell is deselected, you can remove that indexpath from the array.

You should use an array to store checked indices. If you use a single property then only the last selected row will get the correct accessoryType.

I used this code many times (With some minor changes as required)
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:
(NSIndexPath *)indexPath
{
UITableViewCell *thisCell = [tableView cellForRowAtIndexPath:indexPath];
if (thisCell.accessoryType == UITableViewCellAccessoryNone)
{
thisCell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else
{
thisCell.accessoryType = UITableViewCellAccessoryNone;
}
}
- (UITableViewCellAccessoryType)tableView:(UITableView *)tableView
accessoryTypeForRowWithIndexPath:(NSIndexPath *)indexPath
{
//add your own code to set the cell accesory type.
return UITableViewCellAccessoryNone;
}

Related

How to get accessoryType for UItableViewCell?

Please check the below code..
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// I may use this object to maintain check state.
ab_user_info *obj = nil;
obj = [self.listData objectAtIndex: [indexPath row]];
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
cell.accessoryType = UITableViewCellAccessoryCheckmark;
[contact_table reloadData];
}
As per the above code, I have checked all the table I am clicking, What should I do to uncheck again, I know I should change accessory type to None, but when, how do I know previously it was checked? Is there any API which tell us the accessary type of cell.
I have done in other table view by adding an extra member in my modal obj to track the checked and unchecked cell, however I just want to know is there any way without that?
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if (cell.accessoryType == UITableViewCellAccessoryCheckmark)
{
cell.accessoryType = UITableViewCellAccessoryNone;
}
else
{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
tableView is a Data Presenter view object
TableView is just used to 'display' data, it is not the manager or tracker of data. You need to track the attributes of data in the backend. I mean if you want to keep track of which all rows are checked or unchecked, it cannot be managed by TableView, you need to take care of it either by using NSArray or any other object type.
Try below code :
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// I may use this object to maintain check state.
ab_user_info *obj = nil;
obj = [self.listData objectAtIndex: [indexPath row]];
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if (cell.accessoryType == UITableViewCellAccessoryCheckmark) {
cell.accessoryType = UITableViewCellAccessoryNone;
}else{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
}

multiple selection in grouped tableview

I am working with grouped tableview with multiple sections.
and I have to implement the functionality of multiple selection on didselectrow at indexpath
method. my code is as follows.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)path
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:path];
if (cell.accessoryType == UITableViewCellAccessoryCheckmark)
{
cell.accessoryType = UITableViewCellAccessoryNone;
}
else
{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
}
which allows me to select multiple cells
but when I scroll my tableview at that time my selection disappears.
Your selection goes off when you scroll because it calls cellForRowAtIndexPath and there you have not handle selection.
To avoid this problem you can do as follows:
In didSelectRowAtIndexPath you can save index path of selected row as follows:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)path
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:path];
if (cell.accessoryType == UITableViewCellAccessoryCheckmark)
{
cell.accessoryType = UITableViewCellAccessoryNone;
//remove index path
[selectedIndexPathArray removeObject:path];
}
else
{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
[selectedIndexPathArray addObject:path];
}
}
and in cellForRowAtIndexPath you can check whether cell is selected or not.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//If selectedIndexPathArray contains current index path then display checkmark.
if([selectedIndexPathArray containsObject:indexPath])
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
Try this
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil];
if (self.tableView.isEditing) {
cell.selectionStyle = UITableViewCellSelectionStyleBlue;
} else {
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
return cell;
}
-(UITableViewCellEditingStyle) tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath {
return UITableViewCellEditingStyleMultiSelect;
}
-(IBAction) switchEditing {
[self.tableView setEditing:![self.tableView isEditing]];
[self.tableView reloadData]; // force reload to reset selection style
}
Hope this helps solving your problem.(ref)
Your selection disapear cause the method CellForRowAtIndexPath will be called at scroll.
You need to set the accessory again.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
...
// here
...
}
You are getting this issue because you are not tracking your row selections.When the callback method cellForRowAtIndexPath gets called for the rows that had disappeared/(scrolled up/down) the cell object no longer remembers whether it was selected or not. (reason those selections are disappearing)
I would suggest you to use a collection like NSMutableArray/NSArray to track the selected rows.
You can use either of these approaches.
This would be a quick working fix:
Add/Remove the index path object in didSelectRowAtIndexPath based on the users selection
and then based on the contents of that array u can toggle the value of cell.accessoryType for the corresponding cell.
Ideally,you can use a data bean/model with some boolean member called selected and u can update its value based on the selection made.Then instead of simply adding those index path u can add those meaningful data bean objects onto your array and get the selections back from the selected property of the bean.This approach would help u in getting back the row selections even if the user kills and restarts the app provided u persist the bean objects in database/archive..(But it all depends on ur use case and requirements!)
Hope this helped!

Need logic for UITableView's checkmark accessory

I have 5 cells in my tableview. User can select a row which sets the cells' accessory to check marked. They can select multiple rows.
I want to make sure one cell is always check marked. How can I do this? All rows are check marked by default.
Here is the code I use in didSelectRow
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if (cell.accessoryType == UITableViewCellAccessoryNone) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
} else {
cell.accessoryType = UITableViewCellAccessoryNone;
}
[self.tableView deselectRowAtIndexPath:iIndexPath animated:YES];
}
Implement tableView:willDeselectRowAtIndexPath:. If there is only one element selected, return nil to indicate that the table may not deselect it.

Problem: Multiple selection tableview cells being reused

I have a tableview, i need to have a checkmark displayed everytime i select a row. (Multiple selection) My code is given below. I am also able to unselect a row.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *RootViewControllerCell = #"RootViewControllerCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:RootViewControllerCell];
if(nil == cell)
{
cell = [[[UITableViewCell alloc]initWithFrame:CGRectZero reuseIdentifier:RootViewControllerCell] autorelease];
}
cell.textLabel.font = [UIFont fontWithName:[NSString stringWithFormat:#"HelveticaNeue-Bold"] size:12];
textView.textColor = [UIColor colorWithRed:0.281 green:0.731 blue:0.8789 alpha:1];
cell.textLabel.text = [optionsArray objectAtIndex:[indexPath row]];
if (pathIndex == indexPath)
{
if (cell.accessoryType == UITableViewCellAccessoryCheckmark)
{
cell.accessoryType = UITableViewCellAccessoryNone;
}
else {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
}
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
pathIndex = indexPath;
[surveytableView reloadData];
}
But i have a problem with the cells being reused. When i select a cell another cell elsewhere also gets selected. Only the checkmark (or no checkmark) is getting reused other details like the row title, etc., don't get reused. Any solutions to fix this. Thanks in advance.
Add it to cellForRowAtIndexPath:
if ([tableView.indexPathsForSelectedRows containsObject:indexPath]) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
} else if (![tableView.indexPathsForSelectedRows containsObject:indexPath]) {
cell.accessoryType = UITableViewCellAccessoryNone;
}
Worked for me
At your
if (pathIndex == indexPath)
you're comparing pointers not the values of them, try
[pathIndex isEqual:indexPath]
or use
- (NSComparisonResult)compare:(NSIndexPath *)otherObject;
Next you're assigning a value to pathIndex without retaining or copying it like
pathIndex = [indexPath copy];
(of course now since you're retaining the value, before copying your new object you have to release the previous one [pathIndex release];)
Finally, no multiple selection is provided by your implementation, only single selection. You could try adding and removing NSIndexPath objects to an NSMutableArray and check against their presence in your mutable array at cellForRowAtIndexPath instead.
The issue is that you only do something with the accessory if the current row matches pathIndex.... so what if it is a normal cell...? You never set it back. You want...
cell.accessoryType = UITableViewCellAccessoryNone;
if ([pathIndex isEqual:indexPath])
{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
It is good practice to reset the cells before you set any specific properties.

UITableView Checklist Problem

I have this bizarre problem. I'm making a checklist program with XCode and I'm using UITableView with UITableViewCellAccessoryCheckmark. I can select cells and the checkmark will appear, but somehow, other cells that I have NOT yet selected below will also have a checkmark appear. Any ideas?
Here's my check mark coding:
- (void)tableView:(UITableView *)aTableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell;
cell = [aTableView cellForRowAtIndexPath: indexPath];
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
I don't know if this affects it, but I also implemented this method:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"CellIdentifier";
// Dequeue or create a cell of the appropriate type.
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
cell.accessoryType = UITableViewCellAccessoryNone;
}
// Configure the cell.
if(tableView == Table1){
switch(indexPath.section){
case 0:
cell.textLabel.text = [array1 objectAtIndex:indexPath.row];
break;
case 1:
cell.textLabel.text = [array2 objectAtIndex:indexPath.row];
break;
case 2:
cell.textLabel.text = [array3 objectAtIndex:indexPath.row];
break;
}
//cell.textLabel.text = [NSString stringWithFormat:#"Row %d", indexPath.row];
}
if(tableView == Table2){
cell.textLabel.text = [array4 objectAtIndex:indexPath.row];
}
return cell;
}
Thanks.
Set the cell.accessoryType each time you call tableView:cellForRowAtIndexPath:. Otherwise, when you reuse a cell, you'll get it's accessoryView instead of what you're expecting.
So, yeah, you'll need to keep track in when NSIndexPaths are selected by some method other than just looking at the accessoryType.
You should keep the checked/unchecked info in data source (array).
I also advise you to remove the cell.accessoryType = UITableViewCellAccessoryNone; line.
This line will be executed only for few first cells. All the other cells will be "reused" - meaning that the old (already initiated) cells will be used, and you will have to modify the details that are displayed on these cells (all inside cellForRowAtIndexPath as you do now).
In addition you will have to add a similar line (something like cell.accessoryType = ([[array objectAtIndex:indexPath.row] boolValue] ? UITableViewCellAccessoryCheckmark : UITableViewCellAccessoryNone;).
In general, I suggest you to use one array for holding the data for your table, when each item in the array will be a dictionary. This way you will be able to hold the texts and the boolean checkmarks (inside NSNumber) and easily access them when needed.