Checkmark in selected UITableViewCell also showing on non-selected cells - ios

heres my code in didSelectRowAtIndexPath. any suggestion or help on how to fix this please.. the problem is when i clicked the cell many cell will have checkmark ....My plan is when i clicked one cell only that cell will have Checkmark
- (void)tableView:(UITableView *)thetableView
didSelectRowAtIndexPath:(NSIndexPath *)newindexPath {
[thetableView deselectRowAtIndexPath:[thetableView indexPathForSelectedRow]
animated:true];
UITableViewCell *cell = [thetableView cellForRowAtIndexPath:newindexPath];
if (cell.accessoryType == UITableViewCellAccessoryNone) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
} else if (cell.accessoryType == UITableViewCellAccessoryCheckmark) {
cell.accessoryType = UITableViewCellAccessoryNone;
}
}
and heres the code in cellForRowAtIndexPath:
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
object:(nullable PFObject *)object {
static NSString *cellIdentifier = #"attendance";
UITableViewCell *cell =
[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
UILabel *student_lastname = (UILabel *)[cell viewWithTag:1];
UILabel *student_firstname = (UILabel *)[cell viewWithTag:2];
UILabel *student_midname = (UILabel *)[cell viewWithTag:3];
student_lastname.text = object[#"Last_Name"];
student_firstname.text = object[#"First_Name"];
student_midname.text = object[#"Middle_Name"];
UILabel *studentNum = (UILabel *)[cell viewWithTag:5];
studentNum.text = [NSString stringWithFormat:#"%d", indexPath.row];
return cell;
}

So, I am assuming that you only want to show a checkmark if the cell is selected. Recommend you to update your question please.
The problem happens because your cells are being re-used when you scroll and you need to first set the accessory type accordingly in your cellForRowAtIndexPath method like this:
if ([cell isSelected])
cell.accessoryType = UITableViewCellAccessoryCheckmark;
else
cell.accessoryType = UITableViewCellAccessoryNone;
This is to ensure that whenever a cell is reused, you make sure that it does not have any checkmark if its not selected, and show a checkmark if selected.
Next use the following two methods to set the checkmark and remove it when the cell is unselected/selected like this:
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
-(void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
cell.accessoryType = UITableViewCellAccessoryNone;
}
Also, you should not call [thetableView deselectRowAtIndexPath:[thetableView indexPathForSelectedRow] animated:true]; This method is automatically called in your case.
Hope this solves your problem.

Not a fan of either answer provided. Apple's UITableView implementation forces you into MVC (model-view-controller). Cell views, since they can be reused, should never store state, which is what you're doing relying on cell.selected. All answers above will fail if there are more cells than fit on screen, since they will be reused.
Given that you already have an object to store data such as "Last_Name", etc. you should also store #"Selected" as well.
Here's what your code should look like:
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
object:(nullable PFObject *)object {
static NSString *cellIdentifier = #"attendance";
UITableViewCell *cell =
[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
UILabel *student_lastname = (UILabel *)[cell viewWithTag:1];
UILabel *student_firstname = (UILabel *)[cell viewWithTag:2];
UILabel *student_midname = (UILabel *)[cell viewWithTag:3];
student_lastname.text = object[#"Last_Name"];
student_firstname.text = object[#"First_Name"];
student_midname.text = object[#"Middle_Name"];
NSNumber *selectedVal = object[#"Selected"];
if (selectedVal && [selectedVal boolValue]) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
} else {
cell.accessoryType = UITableViewCellAccessoryNone;
}
UILabel *studentNum = (UILabel *)[cell viewWithTag:5];
studentNum.text = [NSString stringWithFormat:#"%d", indexPath.row];
return cell;
}
Then, in didSelect, you change the state of the cell and force a reload (of that cell only, if appropriate).
- (void)tableView:(UITableView *)thetableView
didSelectRowAtIndexPath:(NSIndexPath *)newindexPath {
NSNumber *selectedVal = object[#"Selected"];
BOOL selected = selectedVal ? ![selectedVal boolValue] : YES;
object[#"Selected"] = #(selected);
[thetableView reloadRowsAtIndexPaths:#[newindexPath]
withRowAnimation:UITableViewRowAnimationAutomatic];
}

Related

Selecting one UITableViewCell selects the other cell after scrolling

Even though it's common question but I'm not getting how to fix this.
I referred Selecting one UITableViewCell selects the other cells at that same position when you scroll up or down But i didn't understand.
I'm having allMumbaiArray (using in cellForRowAtIndexPath) and tableview alllMumbaiTableview. By using following code i can select and deselect the row.
UPDATED as per EI Captain's solution
#property (nonatomic, strong) NSMutableArray *arrIndexpaths;
tableView Methods -:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"CellIdentifier"];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"CellIdentifier"];
}
cell.textLabel.text = [allMumbaiArray objectAtIndex:indexPath.row];
if ([self.arrIndexpaths containsObject:[NSNumber numberWithInt:indexPath.row]])
{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else{
cell.accessoryType = UITableViewCellAccessoryNone;
}
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self.view endEditing:YES];
NSString *testing =[allMumbaiArray objectAtIndex:indexPath.row];
UITableViewCell* cell = [tableView cellForRowAtIndexPath:indexPath];
cell.accessoryType = UITableViewCellAccessoryCheckmark;
[self.arrIndexpaths addObject:[NSNumber numberWithInt:indexPath.row]];
NSLog(#"%#",testing);
}
- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *tableViewCell = [tableView cellForRowAtIndexPath:indexPath];
tableViewCell.accessoryType = UITableViewCellAccessoryNone;
[self.arrIndexpaths removeObject:[NSNumber numberWithInt:indexPath.row]];
}
Issue : 1) when i select first row after scrolling the tablewview another row get selected.How to Fix this?
2) After selecting and deselecting row continuously, how can i maintain the only selected row values ?
Here is the solution
make one mutable array that stores selected index of tableview cell..
#property (nonatomic, strong) NSMutableArray *arrIndexpaths;
cellForRowAtIndexPath
if ([self.arrIndexpaths containsObject:[NSNumber numberWithLong: indexPath.row]])
{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else
{
cell.accessoryType = UITableViewCellAccessoryNone;
}
didSelectRowAtIndexPath
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *tableViewCell = [tableView cellForRowAtIndexPath:indexPath];
tableViewCell.accessoryType = UITableViewCellAccessoryCheckmark;
[self.arrIndexpaths addObject:[NSIndexSet indexSetWithIndex:indexPath.row]];
}
didDeselectRowAtIndexPath
- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *tableViewCell = [tableView cellForRowAtIndexPath:indexPath];
tableViewCell.accessoryType = UITableViewCellAccessoryNone;
[self.arrIndexpaths removeObject:[NSIndexSet indexSetWithIndex:indexPath.row]];
}
Here is the sample project...
demo project
If your cell are not showing accessory then you just need to reload them
[_ableView reloadRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationNone];
try this in didSelectRowAtIndexPath and didDeselectRowAtIndexPath.

in didselect row my first row returnig label text instead of my custom label text

here i have a table view where i'm adding custom label which stores some
quiz ids from array
where cell.textlabel.text stores quiz names from array
problem:
when i'm selecting first row in didselectRowAtIndexPath
it returns cell.textlabel.tex but for second row it is returning correct value that is
quiz ids
here is code
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"CellId";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.textLabel.text = [quizname objectAtIndex:indexPath.row];
UILabel *lbl = [[UILabel alloc]init];
lbl.tag=indexPath.row;
[cell addSubview:lbl];
lbl.text = [quizIds objectAtIndex:indexPath.row];
return cell;
}
in did selectrow
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
UILabel *label = (UILabel *) [cell viewWithTag:indexPath.row];
NSString *qid =label.text;
NSLog(#"%#",qid);
}
i'm getting quid is equal to cell.texlabel.text for firsr row but not in others rows
they are getting quiz ids perfectly
any help most valueble for me
Try using customTableViewCell & add your label inside the customCell. Adding UILabel inside cellForRowAtIndexPath is not a good approach.

UITableViewCell that I didn't edit (portion that is not visible) become also edited.

When I put a check mark on a UITableViewCell, the cell I didn't put checkmark (that is not visible) become also checked.
I think that when the tableview reuses cell, something is wrong.
How do I fix it?
- (void)viewDidLoad
{
myTableView = [[UITableView alloc]initWithFrame:CGRectMake(0, 100, 200, 300)];
[myTableView registerClass:[AreaCellInShakeVC class] forCellReuseIdentifier:#"areaCell"];
myTableView.delegate = self;
myTableView.dataSource = self;
myTableView.allowsMultipleSelection = YES;
[self.view addSubview:myTableView];
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString* cellIdentifier = #"Cell";
CustomCell* cell = (CustomCell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[CustomCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
CustomCell* cell = (CustomCell *)[tableView cellForRowAtIndexPath:indexPath];
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
You need to have some logic in your cellForForIndexPath that sets the checkmark accordingly. This also means you need to store the status of the cell somewhere so you can check if it is ticked or not. So, set up an array, with an entry per row, then check that using your indexpath.row value to see if it should be checked or not. For example in cellForRowAtIndexPath have something like this
if ([[selectedRow objectAtIndex:indexPath.row] isEqualToString:#"Y"])
{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else
{
cell.accessoryType = UITableViewCellAccessoryNone;
}
In your didSelectRowAtIndexPath you can then set the check accordingly by
if ([[selectedRow objectAtIndex:indexPath.row] isEqualToString:#"Y"])
{
[selectedRow replaceObjectAtIndex:indexPath.row withObject:#"N"];
}
else
{
[selectedRow replaceObjectAtIndex:indexPath.row withObject:#"Y"];
}
Then do a reloadData on your tableView to update the checkMarks. Hope this helps.
Set up checkmark in cellForRowAtIndexPath like
cell.accessoryType = UITableViewCellAccessoryNone;

UITable View cellForRowAtIndexPath: How to return no cell

I am trying to delete a cell from the table from the table view when no data is returned from Parse. But no matter what I try I can't find any solution to keep from having a blank cell (Cell when no data is passed) ahead of the cell with content.
Here is my code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath object:(PFObject *)object
static NSString *simpleTableIdentifier = #"RecipeCell";
NSString *identifier;
if (indexPath.row == 0) {
identifier = #"Cell";
} else if (indexPath.row == 1) {
identifier = #"Cell2";
}
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
}
// Configure the cell
if (![#"test" isEqual: [object objectForKey:#"teacher"]]){
UILabel *nameLabel = (UILabel*) [cell viewWithTag:101];
nameLabel.text = #"";
UILabel *prepTimeLabel = (UILabel*) [cell viewWithTag:102];
prepTimeLabel.text = #"";
return cell;
} else {
UILabel *nameLabel = (UILabel*) [cell viewWithTag:101];
nameLabel.text = [object objectForKey:#"message"];
UILabel *prepTimeLabel = (UILabel*) [cell viewWithTag:102];
prepTimeLabel.text = [object objectForKey:#"teacher"];
return cell;
}
}
Thanks for any help given!
You cannot control the number of cells in a UITableView from the cellForRowAtIndexPath method - You need to return the correct value from the numberOfRowsInSection method. Refer to the UITableViewDataSource protocol reference and the Table View Programming Guide
Addtionally, this code block -
if (indexPath.row == 0) {
identifier = #"Cell";
} else if (indexPath.row == 1) {
identifier = #"Cell2";
}
is somewhat redundant - all of your cells are UITableViewCellStyleDefault, so they are interchangeable. Using two different identifiers is not necessary - If you intend to use different custom cell types in the future then you can keep this concept, but you probably wouldn't use the indexPath.row directly, rather you would be driven by the data type in your model for the row in question.

TableView repeats first 13 rows

I've got an UITableView with 30 objects.
Controller shows correctly first 13 rows, on 14th row use a "joker" row which changes his content scrolling, then start again with first thirteen row and "joker" row until the end.
That's code of cellForRowAtIndexPath method:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier: #"cell" forIndexPath:indexPath];
UIImageView * flagImageView = (UIImageView *) [self.view viewWithTag:1];
UILabel * nationLabel = (UILabel *) [self.view viewWithTag:2];
nationLabel.text = [_nationsArray objectAtIndex:indexPath.row];
nationLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleBody];
NSLog(#"%i", indexPath.row);
return cell;
}
Strange thing is that configuring cell in if (cell == nil) { ... } it doesn't work...
The problem seems to be with the nationLabel. When I replaced
UILabel * nationLabel = (UILabel *) [self.view viewWithTag:2];
nationLabel.text = [_nationsArray objectAtIndex:indexPath.row];
with
cell.textLabel.text = [_nationsArray objectAtIndex:indexPath.row];
it's working fine (at least the text). So I think you should try to make a UITableViewCell subclass, make property for that label and see if it's ok then.
Don't use this
UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier: #"cell" forIndexPath:indexPath];
Change your code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier: #"cell"];
if(cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"cell"];
}
UIImageView * flagImageView = (UIImageView *) [self.view viewWithTag:1];
UILabel * nationLabel = (UILabel *) [self.view viewWithTag:2];
nationLabel.text = [_nationsArray objectAtIndex:indexPath.row];
nationLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleBody];
NSLog(#"%i", indexPath.row);
return cell;
}

Resources