I have two methods which are changing accerssory type of a cell.
First is called after all cells are loaded, the other one is called when user clicks on any cell.
Second method works fine, it removes checkmark from selected cell. Unfortunately the first one does nothing (I want to add checkmark to one of the cells). It makes me confused, beceause theese methods should work the same, shouldnt they?
// First method
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
if ([indexPath row] == ((NSIndexPath*)[[tableView indexPathsForVisibleRows]
lastObject]).row)
{
LanguageTableViewCell *cell = [self.tableView cellForRowAtIndexPath: [NSIndexPath indexPathForRow:myNumber inSection:0]];
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
}
// Second method
- (void)tableView:(UITableView )tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
LanguageTableViewCell *cell = [tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:myNumber inSection:0]];
cell.accessoryType = UITableViewCellAccessoryNone;
}
I tried to change class of cell, but its still not working. Im not sure if first function is called in right time = after viewDidLoad...
Thanks for help!
You want to use - (__kindofUITableViewCell *)cellForRowAtIndexPath:(NSIndexPath *)indexPath.
Related
So I am trying to pre select the a row in a table using selectRowAtIndexPath.
My question is, where is the best place to call selectRowAtIndexPath?
The only place I thought of calling this, was in cellForRowAtIndexPath:... because I had the indexPath, but that didn't seem to work.
I appreciate any answers or suggestions.
Thanks!
Approach 1 :
For the cell to appear selected, you have to call -setSelected:animated: from within -tableView:willDisplayCell:forRowAtIndexPath: like so:
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (/* Condition */) {
[cell setSelected:YES animated:NO];
}
}
Approach 2 :
- (void)viewDidAppear:(BOOL)animated {
NSIndexPath *indexPath=[NSIndexPath indexPathForRow:0 inSection:0];
[myTableView selectRowAtIndexPath:indexPath animated:YES scrollPosition:UITableViewScrollPositionNone];
}
If you want that particular row to be selected everytime then Approach 1 is better, else if you just want it for selected initially then Approach 2 is better.
Why not just set the cell as selected manually, instead of calling the delegate method?
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"MyCell" forIndexPath:indexPath];
//...
if( /* some condition */ ) {
cell.selected = YES;
}
//...
return cell;
}
This is my code, which shows a problem for 14 rows of a table view. For one screen, 6 cells are visible.
When I tapped the 2nd cell, the 10 cell also has a checkmark, tap 3rd then 11th checkmarked, 1st then 9th checkmarked, tap 1st, then 8th also checkmarked...but the grey highlight does not behave like this, only one cell can be highlighted.
If I tap a cell after one is tapped on the the same screen, the one just checkmarked will be cleared for checkmark, which makes sense. However, if after I tapped one cell and then scroll the tableview lower, I can tap a cell and it shows checkmark as well, i.e. the one just checked on top screen still has a checkmark. So if I scroll up and down, and tap one cell each time after I scroll to the other side, I can put a checkmark for every cell, all checkmarks are shown.
It is really weird, and I have tried a lot of ways to solve it, but seems I have some basic understanding of UITableView missing, can anyone figure it out, please? Thanks.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *ID= #"UITableViewCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID];
}
cell.imageView.image = [UIImage imageNamed:#"earth.png"];
return cell;
}
- (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;
}
You're not storing the existence/absence of your checkmark in any sort of persisted data source and showing/hiding it in cellForRowAtIndexPath. Because of this, your table is reusing your cells, and it just throws it up as it found it. So if it reuses a cell that had your checkmark accessory enabled, it shows it as enabled (because you didn't specifically disable it in cellForRow)
I would keep an NSMutableArray of selected indexPath objects. Add the indexPath in didSelectRowAtIndexPath, and remove it in didDeselectRowAtIndexPath. Then, in cellForRowAtIndexPath, check if the current indexPath exists in the array and enable the checkmark if so, disable if not.
Stonz2's answer is right.
For example, you should create an object for table view data source and it should has a property to show is it checkmarked.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath
{
...
Item *item = [self.itemArray objectAtIndex:indexPath.row];
if (item.checkmarked) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
} else {
cell.accessoryType = UITableViewCellAccessoryNone;
}
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:NO];
Item *tappedItem = [self.itemArray objectAtIndex:indexPath.row];
tappedItem.checkmarked = !tappedItem.checkmarked;
[tableView reloadRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationNone];
}
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.
I want a table which, when you click different rows, they gain or lose a checkmark to show they are either selected or not selected.
Currently my tableview will let me select and deselect different rows. But a checkmark will only appear once I have clicked one and then another. The same happens when I deselect, I click a row with a checkmark then click another row and the checkmark disappears.
Here is my code currently:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString * exerciseChoiceSimpleTableIdentifier = #"ExerciseChoiceSimpleTableIdentifier";
UITableViewCell * exerciseChoiceCell = [tableView dequeueReusableCellWithIdentifier:exerciseChoiceSimpleTableIdentifier];
if (exerciseChoiceCell == nil) {
exerciseChoiceCell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:exerciseChoiceSimpleTableIdentifier];
}
//Here we get each exercise we want to display
BExercise * exercise = [[_data getExerciseCompleteList] objectAtIndex:indexPath.row];
//Name the cell after the exercises we want to display
exerciseChoiceCell.textLabel.text = exercise.name;
return exerciseChoiceCell;
}
-(void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath {
if ([tableView cellForRowAtIndexPath:indexPath].accessoryType == UITableViewCellAccessoryNone)
{
// Uncheck the row
[tableView deselectRowAtIndexPath:indexPath animated:YES];
[tableView cellForRowAtIndexPath:indexPath].accessoryType = UITableViewCellAccessoryCheckmark;
}
else
{
// Check the row
[tableView deselectRowAtIndexPath:indexPath animated:YES];
[tableView cellForRowAtIndexPath:indexPath].accessoryType = UITableViewCellAccessoryNone;
}
}
I think the problem is to do with it being selected rather than touch up inside and deselecting when the finger is released from the button.
I am expecting the answer to be quite straight forward but all the similar questions on stackflow haven't dealt with the checkmarks delayed appearance.
It would be great to understand the root of this problem and how to fix it.
change the method
-(void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath
by
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
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;
}