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.
Related
This question already has answers here:
iOS UITableViewCellAccessoryCheckmark Visible ob every scroll
(4 answers)
Closed 6 years ago.
I've tried every single option available on this website for this problem but none of them seems to be working.
If I scroll down I see the checkmark. If I scroll back up the positioning of my selection is not the same.So as the problem is the same I wanted to open this question for one more time as a fresh start. Here is how I'm doing it:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
myTableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if (![selectedDX containsObject:myMutArray[indexPath.row]])
{
[selectedDX addObject:myMutArray[indexPath.row]];
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
}
- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath {
myTableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if ([selectedDX containsObject:myMutArray[indexPath.row]]) {
[selectedDX removeObject:myMutArray[indexPath.row]];
cell.accessoryType = UITableViewCellAccessoryNone;
}
}
I've also tried it in in a single didSelectRowAtIndexPath method but the result is same.
Do you set the accessory type correctly when you return the cell in cellForRowAtIndexPath? It looks to me that you only set the accessory when the user taps on a cell but this is not enough.
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
[...]
if ([selectedDX containsObject:myMutArray[indexPath.row]])
{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else
{
cell.accessoryType = UITableViewCellAccessoryNone;
}
[...]
}
Your cells are reused when you scroll in your table view. So one cell is reused for more than one of your items. This means the accessory is also reused. So when you scroll and don't remove the accessory from the cell it will still have the checkmark.
You could also reset the accessory in the prepareForReuse method in a custom UITableViewCell subclass
Add condition in cellForRowAtIndexPath
if([selectedDX containsObject:allCodeLabel[indexPath.row]])
{
cell.accessoryType = UITableViewCellAccessoryType.Checkmark
}
else
{
cell.accessoryType = UITableViewCellAccessoryType.None
}
It works for me.Hope it helps :)
you can handle it like this:
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
WCategoriesTableViewCell* cell = [tableView
cellForRowAtIndexPath:indexPath];
if (cell.accessoryType == UITableViewCellAccessoryNone)
cell.accessoryType = UITableViewCellAccessoryCheckmark;
else
cell.accessoryType = UITableViewCellAccessoryNone;
}
I have a UITableView that displays checkmarks when a row is selected. The problem is that When i select a row in didSelectRowAtIndexPath and add a checkmark on the selected row it adds an additional checkmark. Here's my code
Any help would be very much appreciated.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
// Configure the cell...
cell.textLabel.text=[[Model.category objectAtIndex:indexPath.row] categoryName];
cell.imageView.image=[[Model.category objectAtIndex:indexPath.row]categoryImage];
//cell.detailTextLabel.text =#"Breve Descripción de la categoria";
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
if ([self.tableView cellForRowAtIndexPath:indexPath].accessoryType == UITableViewCellAccessoryCheckmark) {
[self.tableView cellForRowAtIndexPath:indexPath].accessoryType =UITableViewCellAccessoryNone;
[self.cellSelected removeObject:indexPath];
}else {
[tableView cellForRowAtIndexPath:indexPath].accessoryType=UITableViewCellAccessoryCheckmark;
[self.cellSelected addObject:indexPath];
}
[self checkMark];
[tableView reloadData];
}
- (void)checkMark{
for (NSIndexPath * indexPath in self.cellSelected) {
[self.tableView cellForRowAtIndexPath:indexPath].accessoryType=UITableViewCellAccessoryCheckmark;
}
}
[self.tableView cellForRowAtIndexPath:indexPath] call in the didSelectRowAtIndexPath will not return the exact cell. It can be same cell, new cell or reused cell. If it is a reused cell at its accessory view has a checkmark, you will end up having two cells with checkmark.
Its better to store in the array and use it accordingly. If you are planning to have multiple selections, Use the code example below.
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.cellSelected = [NSMutableArray array];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//Cell Initialisation here
if ([self.cellSelected containsObject:indexPath])
{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else
{
cell.accessoryType = UITableViewCellAccessoryNone;
}
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
//if you want only one cell to be selected use a local NSIndexPath property instead of array. and use the code below
//self.selectedIndexPath = indexPath;
//the below code will allow multiple selection
if ([self.cellSelected containsObject:indexPath])
{
[self.cellSelected removeObject:indexPath];
}
else
{
[self.cellSelected addObject:indexPath];
}
[tableView reloadData];
}
Try this:
Declare in your .m file:
#interface MyViewController () {
NSIndexPath *__selectedPath;
}
In tableView:cellForRowAtIndexPath: check if given indexPath is the same as stored in ivar:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
//configure cell
if ([__selectedPath isEqual:indexPath]) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
} else {
cell.accessoryType = UITableViewCellAccessoryNone;
}
return cell;
}
In tableView:didSelectRowAtIndexPath store pointer to selected NSIndexPath or nil if cell has been deselect
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (cell.accessoryType == UITableViewCellAccessoryNone) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
__selectedPath = indexPath;
} else {
cell.accessoryType = UITableViewCellAccessoryNone;
__selectedPath = nil;
}
}
I wrote it without checking in Xcode, so there could be some typos, but I show main idea.
In my opinion you shouldn't call [self checkMark]; in your tableView:cellForRowAtIndexPath: method.
Moreover if you want to have only one selected cell at a time, you should't create NSMutableArray to store NSIndexPath. It seems yours cellSelected stores 2 NSIndexPaths at a time, that why you have this strange behaviour.
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;
}
How can I make the cells transparent. I only want to show the selected cells with a checkmark which I have done:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)path {
UITableViewCell *cell = [tableView cellForRowAtIndexPath:path];
if (cell.accessoryType == UITableViewCellAccessoryCheckmark) {
cell.accessoryType = UITableViewCellAccessoryNone;
}
else {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
}
and when I first create the cells I do that next line of code to get rid of the blue background
cell.selectionStyle = UITableViewCellSelectionStyleNone;
but I have a weird issue where it takes 2 clicks to add and remove the checkboxes. Maybe this is not the right way to do it?
You can read about making transparent UITableViewCells here: How to create a UITableViewCell with a transparent background
And as to your second issue, it appears that this is perhaps what you actually want:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)path {
UITableViewCell *cell = [tableView cellForRowAtIndexPath:path];
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)path {
UITableViewCell *cell = [tableView cellForRowAtIndexPath:path];
cell.accessoryType = UITableViewCellAccessoryNone;
}
I have a list which I have using as a check boxes. I have enable or disable Check mark on row on select. But when I scroll the list its make mark row after every 10 rows.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *oldCell = [tableView cellForRowAtIndexPath:indexPath];
if (oldCell.accessoryType == UITableViewCellAccessoryCheckmark)
{
oldCell.accessoryType = UITableViewCellAccessoryNone;
}
else
{
oldCell.accessoryType = UITableViewCellAccessoryCheckmark;
}
}
UItableView reuses the cell in every scroll so using condition as per accessory type is not a good practice. You can Create an NSMutableArray with selected items and Check as per the Condition below.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
if ([selected containsIndex:indexPath.row]) {
[cell setAccessoryType:UITableViewCellAccessoryCheckmark];
} else {
[cell setAccessoryType:UITableViewCellAccessoryNone];
}
// Do the rest of your code
return cell;
}
in didSelectrowAtindexpath method you can Add and remove the Selected items.
Its because UITableView reuses the cell.
So, in the method cellForRowAtIndexPath, you will have to check for a particular cell (of a particular section and row), if it needs to be checked on, provide the accessory type.
If not needed for that cell, provide accessory type as none.
You need to put your logic to set accessory type for cell in cellForRowAtIndexPath, and to identify the cell to mark with check mark you can mark the object in the list in didSelectRowAtIndexPath: or manage an array of selected/unselected objects of the list here.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *selectedCell = [tableView cellForRowAtIndexPath:indexPath];
if ([selectedCell accessoryType] == UITableViewCellAccessoryNone) {
[selectedCell setAccessoryType:UITableViewCellAccessoryCheckmark];
[NSMutableArray addObject:[AnotherMutableArray objectAtIndex:indexPath.row]];
} else {
[selectedCell setAccessoryType:UITableViewCellAccessoryNone];
[NSMutableArray removeObject:[AnotherMutableArray objectAtIndex:indexPath.row]];
}
[tableView deselectRowAtIndexPath:indexPath animated:NO];
}
Also in your viewDidLoad, instantiate you both mutable arrays-
yourmutableArray1 = [[NSMutableArray alloc]init];
yourmutableArray2 = [[NSMutableArray alloc]init];