tapping one row will select multiple rows - select

I have a weird issue in my tableview. I want to select rows and only want to show the checkmark. I have a tableview with multiple sections. Selecting the row and displaying the checkmark is fine, but 10 rows down the tableview, that row will also get selected??? When selecting more than one row, again, 10 lines down, multiple selections appear.
I am using:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)newIndexPath {
[tableView deselectRowAtIndexPath:[tableView indexPathForSelectedRow] animated:NO];
UITableViewCell *cell = [tableView cellForRowAtIndexPath:newIndexPath];
if (cell.accessoryType == UITableViewCellAccessoryNone) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
// Reflect selection in data model
} else if (cell.accessoryType == UITableViewCellAccessoryCheckmark) {
cell.accessoryType = UITableViewCellAccessoryNone;
// Reflect deselection in data model
}
}

That's not another row being selected, that's the same check-marked cell being reused. In tableView:didSelectRowAtIndexPath: you are using the cell to store state. In tableView:cellForRowAtIndexPath: you are not addressing whether the row should have a check mark or not.
What you will likely want to do is have an ivar NSMutableSet and in didSelectRow.. either add or remove the indexPath from the set, depending on it's checked status. Then in cellForRow.. set the accessoryType property based on the indexPath's membership in the set.
Edit Sorry I didn't catch the comments where you save the state to in a data model. In that case all you have to do is add the check in cellForRow.... Since this is a common question I'll leave the original answer up.

Related

Setting Max IndexPath higher than 10?

I've ran into a problem when creating a checklist in my latest app.
When I call didSelectRowAtIndexPath, it changes an imageView in a CustomCell. So when I click a row in my table, it switches the CustomCell image to a checkmark. It works fine, however, when I scroll down, I notice that it also set some of the other rows in my checklist. I've got it figured out that if I touch row #1...it then updates 1, 11, 21, 31, 41, etc.
How do I get it to JUST change the image on row #1? Does IndexPath max out at 10 somehow?
Thanks!!
didSelectRowAtIndexPath Code:
{
CustomCell *cell = (CustomCell *) [resultsTable cellForRowAtIndexPath:indexPath];
cell.puckSelect.image = [UIImage imageNamed:#"puck_c.png"];
[cell setNeedsDisplay]
}
My list has thousands of items, is that effecting this?
This is because your cells are being reused as you scroll through the list. Don't store state in a cell (i.e. which cell is selected)!
Always read the state of a cell from a data structure (NSArray etc).
What I tend to do is this:
In didSelectRowAtIndexPath, make a change to the data structure (e.g. set 'isSelected' for row 23 to YES)
Then use reloadRowsAtIndexPaths to force the table to reload this row
In cellForRowAtIndexPath, read from the data structure to decide if this row has a tick.
You're seeing cell reuse at work. When you want to change state, you cannot just update the cell itself, because iOS will recycle the cell when it goes off-screen and will reuse it in another row. You must make a record somehow of which rows are checked, and when a cell is prepared for display in -tableView:cellForRowAtIndexPath, set the value of puckSelect.image appropriately.
You can either change you data source in didSelectRowAtIndexPath, or set the value of a property that you check in cellForRowAtIndexPath. Something like this:
- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
cell.textLabel.text = [self.theData objectAtIndex:indexPath.row];
if (indexPath.row == self.checkedIndexPath.row) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}else{
cell.accessoryType = UITableViewCellAccessoryNone;
}
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
self.checkedIndexPath = indexPath;
[tableView reloadData];
}

Multiple Value Selection / Deselection in iPhone

I have multiple values for user selection.
When user selects multiple options then it should be saved in the array.
When user deselects the value then it should remove the same from the array.
How can it be done?
There can be any random selection and deselection from the options.
How can it be done?
Assuming that you want to do this using a table view, you can maintain an mutable array of selected index paths. You can set accessory type to check mark to indicate selection.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if ( [array indexOfObject:indexPath] == NSNotFound ) {
[array addObject:indexPath];
cell.accessoryType = UITableViewCellAccessoryCheckmark;
} else {
[array removeObject:indexPath];
cell.accessoryType = UITableViewCellAccessoryNone;
}
}
and use the array to set the accessoryType properly during cell initialization.
Create a Model class named Options and place all your options as member variables. Update these variables when a user changes the value for any option. Use this variable to port your data from one object to other. Hope this will help you. If it is necessary for you to store the values in a Array then give me some more details about your requirement so we can think further.

problem in cell.accessoryType in UITableView

In my app if user press on any cell in UITableView then accessoryType of cell will be set to check mark like following
-(void)Check:(UITableView *)tableView Mark:(NSIndexPath *)indexPath
{
[self.tableView cellForRowAtIndexPath:indexPath].accessoryType = UITableViewCellAccessoryCheckmark;
buttonCount++;
[selectedCellArray addObject:indexPath];
}
and if user press the same cell then uncheck will happen as follows
-(void)UnCheck:(UITableView *)tableView Mark:(NSIndexPath *)indexPath
{
[self.tableView cellForRowAtIndexPath:indexPath].accessoryType = UITableViewCellAccessoryNone;
buttonCount--;
if (buttonCount == 0) {
[selectedCellArray removeAllObjects];
}
}
and i am calling this
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if([tableView cellForRowAtIndexPath:indexPath].accessoryType == UITableViewCellAccessoryCheckmark)
{
[self UnCheck:tableView Mark:indexPath];
}
else
{
[self Check:tableView Mark:indexPath];
}
Problem is when i am pressing on 1st cell it call Check method and mark the cell to but when i am scroll down i find 2-3 more cheked cell ...even i did not select those cell...i dont know why and how it checked automatically ...
i hope some one know where is the problem
thank you very much
Because cells will be reused by the tableview. Also set the checkmark/accessory type in your tableView:cellForRowAtIndexPath: method.
ya.. I see this happen a lot.
the correct pattern to manage the UITableViewCell state is NOT to directly manipulate the TableViewCell to update the UI, and always set, draw and create the correct state from cellForRowAtIndexPath (or tableView:willDisplayCell:forRowAtIndexPath:)
Meaning, if the user clicks on the cell and you need to update the UI of that cell, store the new state of that cell in an array or dictionary (I find that an NSMutableDictionary with the NSIndexPath as the key works very well).
then call the reloadRowsAtIndexPaths:withRowAnimation: or just [tableView reloadData] so that the cellForRowAtIndexPath reads that array or Dictionary and correctly draws the cell.
otherwise, the cellForRowAtIndexPath will constantly overwrite your changes and use recycled cells that hold incorrect state.
one exception to this rule would be if you would like a nice animation between the two states... if that is the case, save off your new state, perform your animation right there on the cell, then when the animation completes, call the same reloadRowsAtIndexPaths:withRowAnimation or reloadData so that the cell is redrawn in its new state.

UITableView Cell with CheckMarks

I have got an iphone project that has a UITableView which is populated from Core Data..
When a cell is selected, the user is directed to a new view controller (see code line below) which shows additional information about that cell entry (from core data)
[self presentModalViewController:noteViewController animated:YES]
What i want to do is to be able to set some sort of checkmark on either side of each cell to represent whether the task is complete of incomplete..
I have read that i could do this using:
UITableViewCellAccessoryCheckmark
but i am not sure how to implement is as currently
didSelectRowAtIndexPath:
is being used to present the modal view controller..
So essentially i want to know if there is a method for changing the state of a cell's accessory from checkmark to nothing (and vice versa) independently.. in the sense that if the actual checkmark is touch.. it shows it.. and if it is touched again, it hides it..
Any help would be greatly appreciated!
You will need to track selected rows externally from Cell presentation. This means, your model (that you used to build the cells in the first place) will need to track some sort of boolean. Once you have that you set accessoryType to the proper type.
i.e.
if ([[data objectAtIndex:indexPath.row] isSelected]) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
} else {
cell.accessoryType = UITableViewCellAccessoryNone;
}
This would be some of the logic in your:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *selectedCell = [tableView cellForRowAtIndexPath:indexPath];
if (selectedCell.accessoryType == UITableViewCellAccessoryNone)
{
selectedCell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else
if (selectedCell.accessoryType == UITableViewCellAccessoryCheckmark)
{
selectedCell.accessoryType = UITableViewCellAccessoryNone;
}
//Do something
}
Hope this helps
UPDATE
This tutorial will give you a basic info on custom table view cell.
Another Reference.
I think this will give you the solution.

Wrong Editing Controls Displayed in UITableView

I'm having a strange problem with UITableView. When the user taps the Edit button, the tableview (which is a grouped view with multiple sections) is supposed to show delete buttons for each row--except for the final row in each section, which has a green add button.
When a user taps the green button, a new row is inserted, but now the final row gets a delete button. Even stranger, that delete button ACTS like an add button. So it seems there's a drawing glitch, rather than a problem in assigning the correct style. (Extensive NSLogging shows that the last cell is getting the Insert editing style correctly.)
I've tried setting setNeedsDisplay on the cell and the tableView, I've tried reloading that section/row/the entire table, but the issue persists. Any ideas on how to get UITableView to explicitly redraw the editing controls?
I had the same problem. It seems like the cell's gets reused too much..
You could fix it by enforcing new cells for the inserted cells by using different identifiers:
if([tableView isEditing] && indexPath.row == [items count]){
static NSString *CellIdentifier = #"AddCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// "add-cell" setup here.. e.g"
[[cell textLabel] setText:#"Tab to add new item"];
return cell;
}else{
static NSString *CellIdentifier = #"NormalCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// normal cell setup here..
return cell;
}
I'm pretty sure you can just implement this in your UITableView delegate to prevent it from editing the last row:
-(BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
// Return NO if you do not want the specified item to be editable.
if (indexPath.row != lastRow) // whatever your last row is
return YES;
}
return NO;
}