I'm getting a weird problem with table view in iOS. In the table, when I click on a row, I want a checkmark to be displayed, it is working very fine with the code below:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
if([tableView cellForRowAtIndexPath:indexPath].accessoryType == UITableViewCellAccessoryCheckmark){
[tableView cellForRowAtIndexPath:indexPath].accessoryType = UITableViewCellAccessoryNone;
}else{
[tableView cellForRowAtIndexPath:indexPath].accessoryType = UITableViewCellAccessoryCheckmark;
}
}
Right now, my table has 11 rows. When I click on the 1st row, the checkmark appears for the 1st row (this is good) but it also appears for the 10th row. When I click on the 2nd row, the 2nd(this is good) and the 11th appears.
Does anyone has an idea about this issue?
Do this...
self.tableView.allowsMultipleSelection = YES;
Then when you need to get all the selected rows...
NSArray *selectedIndexPaths = [self.tableView indexPathsForSelectedRows];
This array will contain all the rows with the checkmarks on them.
No need to do anything in code yourself.
For the same thing what you are trying to do, I implemented it in following way -
Declare a NSIndexPath Variable in AppDelegate or in local file.
if (Appdelegate.selectedIndexPath == (id)[NSNull null]) {
NSLog(#"null");
Appdelegate.selectedWebsiteIndex=indexPath;
UITableViewCell *cell = [aTableView cellForRowAtIndexPath:indexPath];
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}else{
UITableViewCell *cell1 = [aTableView cellForRowAtIndexPath: Appdelegate.selectedIndexPath];
cell1.accessoryType = UITableViewCellAccessoryNone;
Appdelegate.selectedIndexPath =indexPath;
UITableViewCell *cell = [aTableView cellForRowAtIndexPath:indexPath];
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
Hope This helps you..
Related
In my UITableView called _selectAttributes I want to put and remove a checkmark when I tap on each cell.
This is the code:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell * cell = [_selectAttributes cellForRowAtIndexPath:indexPath];
if (cell.accessoryType != UITableViewCellAccessoryCheckmark) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else {
cell.accessoryType = UITableViewCellAccessoryNone;
}
}
Everything seems to work well, but when I scroll up and down the table, checkmarks appear on other cells and disappear on the previous ones.
How can I solve?
Thank you in advance.
Declare an NSIndexPath property named selectedIndexPath.
Then have your delegate methods cellForRowAtIndexPath and didSelectRowAtIndexPath like this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
...
if ([indexPath isEqual:self.selectedIndexPath])
{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else
{
cell.accessoryType = UITableViewCellAccessoryNone;
}
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:self.selectedIndexPath];
cell.accessoryType = UITableViewCellAccessoryNone;
cell = [tableView cellForRowAtIndexPath:indexPath];
cell.accessoryType = UITableViewCellAccessoryCheckmark;
[tableView deselectRowAtIndexPath:indexPath animated:YES];
self.selectedIndexPath = indexPath;
}
UPDATE:
I wasn't paying attention that you want solution for multiple cell selection. My answer obviously solves problem only for single cell selection, but I believe its a good start.
I would create an NSArray of selected index paths. On tableView:didSelectRowAtIndexPath:, add the index path to that array and in tableView:cellForRowAtIndexPath: check whether the index path is in the array and set the UITableViewCell's accessory type accordingly.
Alright so I'm using a cell reuse identifier to generate UITableViewCells on my table view. This UITableView displays all of your contacts first and last names, first by grabbing them through ABAddressBook and then using the data in cellForRowAtIndexPath: like this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"inviteCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// forIndexPath:indexPath]; taken from above
if(tableView == self.tableView)
{
//configure the cells for the contacts tableView
#define CHECK_NULL_STRING(str) ([str isKindOfClass:[NSNull class]] || !str)?#"":str
id p=[contactsObjects objectAtIndex:indexPath.row];
NSString *fName=(__bridge NSString *)(ABRecordCopyValue((__bridge ABRecordRef)(p), kABPersonSortByFirstName));
NSString *lName=(__bridge NSString *)(ABRecordCopyValue((__bridge ABRecordRef)(p), kABPersonSortByLastName));
cell.textLabel.text=[NSString stringWithFormat:#"%# %#",CHECK_NULL_STRING(fName),CHECK_NULL_STRING(lName)];
}
else
{
//configure the cells for the search bar controller's tableView.
#define CHECK_NULL_STRING(str) ([str isKindOfClass:[NSNull class]] || !str)?#"":str
id p=[searchResults objectAtIndex:indexPath.row];
NSString *fName=(__bridge NSString *)(ABRecordCopyValue((__bridge ABRecordRef)(p), kABPersonSortByFirstName));
NSString *lName=(__bridge NSString *)(ABRecordCopyValue((__bridge ABRecordRef)(p), kABPersonSortByLastName));
cell.textLabel.text=[NSString stringWithFormat:#"%# %#",CHECK_NULL_STRING(fName),CHECK_NULL_STRING(lName)];
}
return cell;
}
What I need to do is, select any of the cells generated like this, and also be able to deselect any of the cells. In the background, I'll be using the phone numbers associated with each name to check if they're registered in my database. But as for this UITableView I need to select any of the table cell's, and not also select every 10th cell, or whatever it is.
Put clearly: I need to keep track of what cells are checked, and I need to do this using minimal code. I may be wrong, but I believe in my case, I MUST USE cell reuse identifiers, and the cells must me "single-selected" and un-selectable. How do I do this?
If i understood correctly.. you need only a single selection on the tableview. Once a new row is selected you deselect the old one.
You can do this like so :
cellForRowAtIndexPath do some thing like this.
if(indexPath.row == 0){
cell.accessoryType = UITableViewCellAccessoryCheckmark;
self.lastSelected = indexPath;//This will keep track of the last selected cell .
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if([self.lastSelected compare:indexPath] == NSOrderedSame){
[tableView deselectRowAtIndexPath:indexPath animated:NO];//This is to remove the highlight on cell selection
return;
} else {
[tableView cellForRowAtIndexPath:indexPath].accessoryType = UITableViewCellAccessoryCheckmark;
[tableView cellForRowAtIndexPath:self.lastSelected].accessoryType = UITableViewCellAccessoryNone;
[self setLastSelected:nil];//Releasing the old retain and resetting
self.lastSelected = indexPath;
[tableView deselectRowAtIndexPath:indexPath animated:NO];
}
}
Hope this helps
EDIT :
Ok now i understood your question. my edited answer is given below
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([tableView cellForRowAtIndexPath:indexPath].accessoryType == UITableViewCellAccessoryCheckmark) {
[tableView cellForRowAtIndexPath:indexPath].accessoryType = UITableViewCellAccessoryNone;
} else
[tableView cellForRowAtIndexPath:indexPath].accessoryType = UITableViewCellAccessoryCheckmark;
}
This way you can select multiple cells and deselect any cell which was earlier selected.
The checkmark will be enabled or disabled depending on its earlier state.
Hope i have the correct understanding of what you wish to do.
I'm new to iOS and I'm having issues with adding/removing a cell accessoryTypeCheckmark when a user selects a cell. I have a friends list in a UITableView and the user should be able to select multiple friends and have a checkmark appear next to them. If the user taps on a friend that has already been selected, the checkmark should disappear. I am keeping track of the friends that have been selected in a NSMutableArray titled 'friends_selected'.
I have the cellForRowAtIndex path set up to check if the friends_selected array contains the username, and if so add a checkmark.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
FriendsListCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
cell.usernameID.text = [self.friends_username objectAtIndex:indexPath.row];
if ([self.friends_selected containsObject:cell.usernameID.text]) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else {
cell.accessoryType = UITableViewCellAccessoryNone;
}
return cell;
}
In my didSelectRowAtIndexPath I am adding or removing the username from the friends_selected array and reloading the table data.
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
FriendsListCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
cell.usernameID.text = [self.friends_username objectAtIndex:indexPath.row];
if ([self.friends_selected containsObject:cell.usernameID.text]) {
[self.friends_selected removeObject:cell.usernameID.text];
}
else {
[self.friends_selected addObject:cell.usernameID.text];
}
[tableView reloadData];
}
Right now the friends_selected array is correctly updating with which usernames have been selected or deselected. There are no checkmarks appearing, however the cell will become highlighted when selected and will remain highlighted even if unselected. Any help would be great, I've been stuck all day on this issue that seems like a simple solution.
In your didSelectRow... method you should replace:
FriendsListCell *cell = (FriendsListCell *)[tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
with:
FriendsListCell *cell = (FriendsListCell *)[tableView cellForRowAtIndexPath:indexPath];
You don't want a new cell, you want the actual cell for the selected row.
And do not call reloadData too. Either update the cell directly or just call reloadData, not both.
When adding a checkmark to selected table cells, im seeing check appear in other cells also.
my didSelectRowAtIndexPathCode is:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
PFObject *player = [squadListArray objectAtIndex:indexPath.row];
NSString *playerName = [player valueForKey:#"fullName"];
NSLog(#"%#", playerName);
UITableViewCell *selectedCell = [tableView cellForRowAtIndexPath:indexPath];
selectedCell.accessoryType = UITableViewCellAccessoryCheckmark;
}
The NSLog has expect results, only showing the one selection.
Any ideas? Do you need me to show any other code?
Thanks
In your cellForRowAtIndexPath you can't be configuring the cell properly when the cell gets reused. You should always be setting (and resetting) all of the properties of the cell from your data model.
You must have a data model that is being used to tell the table view how many rows it has and what each cell should look like. During didSelectRowAtIndexPath you should be updating your data model with the selected information. Then, in cellForRowAtIndexPath, you can use the information in the data model to decide if the cell has a checkmark or not. If it does you add it, if it doesn't you explicitly remove it (to prevent it being left there if the cell was reused).
Your cell is being recycled by other rows. In the method, cellforrowatindexpath, add the following line at the end:
selectedCell.accessoryType = UITableViewCellAccessoryNone;
Cells are cached and re-used. You need to only save the fact you were selected (maybe in PFObject) and then set the accessory each time you configure a cell.
You need to explicitly tell that you don't want other cells to have the checkmark.
if ([self shouldSelectCell]) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
} else {
cell.accessoryType = UITableViewCellAccessoryNone;
}
You could try doing the following:
Create NSMutableSet that holds the indexes of selected cells.
#property(strong, nonatomic) NSMutableSet *selectedCells;
-(NSMutableSet *)selectedCells{
if(_selectedCells){
return _selectedCells;
}
_selectedCells = [[NSMutableSet alloc]init];
return _selectedCells;
}
On didSelect update the set and select the cell:
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
cell.accessoryType = UITableViewCellAccessoryCheckmark;
[self.selectedCells addObject:indexPath];
[tableView selectRowAtIndexPath:indexPath animated:YES scrollPosition:UITableViewScrollPositionMiddle];
}
Remove the indexPath on didDEselect
-(void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
cell.accessoryType = UITableViewCellAccessoryNone;
[self.selectedCells removeObject:indexPath];
}
Inside the
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
update the cell as:
if([self.selectedCells containsObject:indexPath]){
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}else{
cell.accessoryType = UITableViewCellAccessoryNone;
}
I want to use the Checkmark as an toggle switch to let user selects a bundle of items, but this is not working as expected - I have to tap the cell 2 times for the cell to toggle checkmark on/off. And if I do [tableView reloadData] instead of reloadRowsAtIndexPaths it does not work at all.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if (cell.accessoryType == UITableViewCellAccessoryCheckmark) {
cell.accessoryType = UITableViewCellAccessoryNone;
} else if (cell.accessoryType == UITableViewCellAccessoryNone) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
[tableView reloadRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationNone];
}
Your code is changing the view property and then reloading the table view from your model data. You should be changing the model data instead of the view property before you do the reload.