Hi I'm new to this iPhone dev and I have a question about reloadRowsAtIndexPaths. When the user taps one cell, it will expand showing buttons underneath it and tapping it again closes the cell. This works fine when opening and closing cell one at a time, but I have this weird animation when tapping cells in sequence like cell one is tapped, cell 2 is tapped the animation gets weird. Please see the video to fully understand the situation and sorry for the low quality.
http://www.youtube.com/watch?v=R28Rmti9wPQ
and here's the code for reloading the cells
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:
(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:YES];
selectedIndexPath = indexPath;
//close the selected cell if it's open
if(selectedIndex == indexPath.row)
{
selectedIndexPath = nil;
[tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
selectedIndex = -1;
selectedIndexPath = indexPath;
return;
}
//this will reload the previously open cell to avoid it from being recycled
if(selectedIndex >= 0)
{
NSIndexPath *previousPath = [NSIndexPath indexPathForRow:selectedIndex inSection:0];
selectedIndex = indexPath.row;
[tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:previousPath] withRowAnimation:UITableViewRowAnimationFade];
}
//now reload the selected cell
if(selectedIndexPath != nil && [selectedIndexPath isEqual:indexPath]) {
[tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
}
and here's the code for creating the cellForRowAtIndexPath.
if(selectedIndexPath != nil && [selectedIndexPath isEqual:indexPath]) {
selectedIndex = indexPath.row;
static NSString *CustomCellIdentifier = #"CustomCell";
CustomCell *customCell = (CustomCell *)[tableView dequeueReusableCellWithIdentifier: CustomCellIdentifier];
if (customCell == nil) {
customCell = [[[CustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CustomCellIdentifier] autorelease];
}
customCell.locationLabelOutlet.text = [usgsFeeds objectAtIndex:[indexPath row]];
customCell.dateLabelOutlet.text = [pubDateArr objectAtIndex:[indexPath row]];
float thisMag;
thisMag = [(NSNumber *)[magnitudeArr objectAtIndex:[indexPath row]] floatValue];
customCell.magnitudeImageOutlet.image = [self imageForMagnitude:thisMag];
[customCell setSelectionStyle:UITableViewCellSelectionStyleNone];
return customCell;
}
else{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
locationLabel = [[[UILabel alloc] initWithFrame:CGRectMake(10, 3, 225, 20)] autorelease];
locationLabel.tag = kLocationLabelTag;
locationLabel.font = [UIFont fontWithName:#"Helvetica-Bold" size:14.0];
locationLabel.backgroundColor = [UIColor clearColor];
[cell.contentView addSubview:locationLabel];
//and all other views for the cell....
Try reloading both the cell you just selected and the one that was selected before.
This is how I solved a similar problem in my own app.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
if( selectedPath == indexPath)
{
return;
}
showNutritionInfo = NO;
NSIndexPath *oldSelectedPath = selectedPath;
selectedPath = indexPath;
[tableView reloadRowsAtIndexPaths:[NSArray arrayWithObjects:indexPath, oldSelectedPath,nil] withRowAnimation:UITableViewRowAnimationFade]; }
Related
I am displaying certain information in a tableview. These are basically Exam rooms. I am using this logic in order to put the check marks for selecting the particular room. The code is as follows:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath
*)indexPath {
static NSString *CellIdentifier = #"CellIdentifier";
// intializing tableview cell.
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier] autorelease];
}
// Setting tableviewcell title from Room array.
cell.textLabel.text = [NSString stringWithFormat:#"%#",[[arr_roomList
objectAtIndex:indexPath.row] valueForKey:#"description"]];
/* checking the condition if checkedIndexPath is != null.
means at first time checkedIndexPath= null.*/
if (self.checkedIndexPath) {
/* checking the condition if current cell is selected then
we have to show the UITableViewCellAccessoryCheckmark (checkmark on right side of the
cell).*/
if([self.checkedIndexPath isEqual:indexPath])
{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else
{
cell.accessoryType = UITableViewCellAccessoryNone;
}
}
else{
if ([[[arr_roomList objectAtIndex:indexPath.row] valueForKey:#"resource_id"]
isEqualToString:self.str_selected_resourceId]) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
}
// This Method will set the Background and Selected Background Image for the cell.
[[AppDelegate sharedInstance] SetBackgroundImageForcell:cell];
if ([[[arr_roomList objectAtIndex:indexPath.row] valueForKey:#"rec_type"] isEqualToString:#"R"]) {
cell.backgroundColor = [UIColor grayColor];
}
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
/* checking the condition if checkedIndexPath is != null.
means at first time checkedIndexPath= null.*/
if(self.checkedIndexPath)
{
UITableViewCell* uncheckCell = [tableView
cellForRowAtIndexPath:self.checkedIndexPath];
uncheckCell.accessoryType = UITableViewCellAccessoryNone;
}
UITableViewCell* cell = [tableView cellForRowAtIndexPath:indexPath];
cell.accessoryType = UITableViewCellAccessoryCheckmark;
self.checkedIndexPath = indexPath;
[self changeRoomWithResourceId:[[arr_roomList objectAtIndex:indexPath.row]
valueForKey:#"resource_id"]];
}
As I am scrolling down the table the check marks are repeating themselves for any cell randomly. Please Help me as this issue is taking lot of time for me.
You have to clear out any checkmarks that might be placed already, because UITableView reuses cells and does not do it automatically:
// ...
if ([[[arr_roomList objectAtIndex:indexPath.row] valueForKey:#"resource_id"]
isEqualToString:self.str_selected_resourceId]) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
// add this
else
{
cell.accessoryType = UITableViewCellAccessoryNone;
}
I want to implement Checklist for a single selection in a UITableView. Also, I need a cell to be selected by default. Here's my implementation in cellForRowAtIndexPath:
NSUInteger row = [indexPath row];
NSUInteger oldRow = [lastIndexPath row];
cell.accessoryType = (row == oldRow && lastIndexPath != nil) ? UITableViewCellAccessoryCheckmark : UITableViewCellAccessoryNone;
if (indexPath.row == selectedRow ) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else {
cell.accessoryType = UITableViewCellAccessoryNone;
}
didSelectRowAtIndexPath has this code:
if (!self.lastIndexPath) {
self.lastIndexPath = indexPath;
}
if ([self.lastIndexPath row] != [indexPath row])
{
UITableViewCell *newCell = [tableView cellForRowAtIndexPath: indexPath];
newCell.accessoryType = UITableViewCellAccessoryCheckmark;
UITableViewCell *oldCell = [tableView cellForRowAtIndexPath:self.lastIndexPath];
oldCell.accessoryType = UITableViewCellAccessoryNone;
self.lastIndexPath = indexPath;
}
else {
UITableViewCell *newCell = [tableView cellForRowAtIndexPath: indexPath];
newCell.accessoryType = UITableViewCellAccessoryCheckmark;
}
With this code I'm able to get a default checkmark, but whenever I select another row
the first one remains selected until I don't click that cell. So, If I want to select my desired result what should I do?
`
I think the code is a little too complicated. All you need is a single property:
NSInteger _selectedRow;
This, when initially defined, will provide a default selected row. And it will also maintain the previous selection (when looking for the cell to 'unselect'):
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CELL_IDENTIFIER];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CELL_IDENTIFIER];
}
if ([indexPath row] == _selectedRow) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
cell.textLabel.text = [NSString stringWithFormat:#"Row %d", indexPath.row];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (_selectedRow >= 0) {
[tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:_selectedRow inSection:0]].accessoryType = UITableViewCellAccessoryNone;
}
_selectedRow = [indexPath row];
[tableView cellForRowAtIndexPath:indexPath].accessoryType = UITableViewCellAccessoryCheckmark;
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
When this view is created, if you assign:
_selectedRow = 1;
Then the second row will automatically be selected. A value of -1 indicates no default selection, and the two above methods will automatically add/remove the checkmarks from tapped rows.
I know how to handle with cellaccesory type check mark, here I want a button to Uncheck the entire tablecell which are checkmarked? Here my code, can any one please help me to code
- (void)viewDidAppear:(BOOL)animated
{
UIBarButtonItem *rest = [[UIBarButtonItem alloc]initWithTitle: #"RESET" style: UIBarButtonItemStyleBordered target: self action: #selector(uncheckCells)];
UIBarButtonItem *flexibleSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
[toolbar setItems:[NSArray arrayWithObjects:rest,flexibleSpace,flexibleSpace,home,nil]];
[self.navigationController.view addSubview:toolbar];
[self.tableView reloadData];
}
Here the code for my functions
-(void)uncheckCells//unchecking function
{
[self.tableView reloadData];//HERE WHAT SHOULD I DO
}
-(void)hom
{
[self dismissModalViewControllerAnimated:YES];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
cell.textLabel.text = [ar objectAtIndex:indexPath.row];
cell.selectionStyle=UITableViewCellSelectionStyleNone;
if(cell.accessoryType==UITableViewCellAccessoryCheckmark)
{
cell.backgroundColor=UIColorFromRGB(0xd05818);
cell.detailTextLabel.text=#"packed";
cell.detailTextLabel.textColor=[UIColor cyanColor];
}
else
{
cell.backgroundColor=[UIColor whiteColor];
cell.detailTextLabel.text=#"";
}
return cell;
[self.tableView reloadData];
}
(void) deselect
{
[self.tableView deselectRowAtIndexPath:[self.tableView indexPathForSelectedRow] animated:YES];
}
(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView reloadData];
[tableView deselectRowAtIndexPath:indexPath animated:NO];
printf("User selected row %d\n", [indexPath row] + 1);
if ([[tableView cellForRowAtIndexPath:indexPath] accessoryType] == UITableViewCellAccessoryCheckmark)
{
[[tableView cellForRowAtIndexPath:indexPath]setAccessoryType:UITableViewCellAccessoryNone];
}
else
[[tableView cellForRowAtIndexPath:indexPath]setAccessoryType:UITableViewCellAccessoryCheckmark];
[self performSelector:#selector(deselect) withObject:nil afterDelay:0.0f];
[tableView reloadData];
}
If you're doing checkmarks on didSelectRowAtIndexPath: method. A reloadData will work for you.
For eg.
Say you have a button with selector uncheckCells
-(void)uncheckCells
{
[self.tableView reloadData];
}
This should work you.
EDIT: add cell.accessoryType = UITableViewCellAccessoryNone; in your if (cell == nil) condition.
Or do this:
-(void)uncheckCells
{
for (int section = 0, sectionCount = self.tableView.numberOfSections; section < sectionCount; ++section) {
for (int row = 0, rowCount = [self.tableView numberOfRowsInSection:section]; row < rowCount; ++row) {
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:row inSection:section]];
cell.accessoryType = UITableViewCellAccessoryNone;
cell.accessoryView = nil;
}
}
}
I hope it will work.
From reading your code, it looks like you are setting the checkmark on the table view itself.
What you should really be doing is storing whether or not a cell has a check mark in your data source, and using this information in the tableView:cellForRowAtIndexPath: method to display a checkmark or not.
And your deselect method should be going through you datasource and unsetting whatever marker you have there that says whether or not your tableview has a check mark.
That way, when you scroll a tableview, or just call [tableView reloadData]; your datastore will be used to decide whether or not to display a checkmark or not.
I create a tableview with 20 cells.
And when I select first row, it will show checkmark on it.
But when I scroll tableview, then it not only one checkmark on tableview cell.
It also show on another cell.
What's the problem with this?
self.dataAry = [NSArray arrayWithObjects:#"0",#"1",#"2",#"3",#"4",#"5",#"6",#"7",#"8",#"9",#"10",#"11",#"12",#"13",#"14",#"15",#"16",#"17",#"18",#"19",nil];
marks = [NSMutableArray new];
for (int i = 0 ; i < [self.dataAry count]; i++) {
[marks addObject:#"NO"];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
cell.textLabel.text = [dataAry objectAtIndex:indexPath.row];
if ([[marks objectAtIndex:indexPath.row] isEqualToString:#"YES"]) {
[cell setAccessoryType:UITableViewCellAccessoryCheckmark];
}else {
[cell setAccessoryType:UITableViewCellAccessoryNone];
}
// Configure the cell.
return cell;}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *thisCell = [tableView cellForRowAtIndexPath:indexPath];
if ([[tableView cellForRowAtIndexPath:indexPath] accessoryType] == UITableViewCellAccessoryCheckmark){
[[tableView cellForRowAtIndexPath:indexPath] setAccessoryType:UITableViewCellAccessoryNone];
[selectArray removeObject:[self.dataAry objectAtIndex:indexPath.row]];
[marks replaceObjectAtIndex:indexPath.row withObject:#"NO"];
}
else {
[[tableView cellForRowAtIndexPath:indexPath] setAccessoryType:UITableViewCellAccessoryCheckmark];
[selectArray addObject:[self.dataAry objectAtIndex:indexPath.row]];
[marks replaceObjectAtIndex:indexPath.row withObject:#"YES"];
}
}
I think it is due to reusing the checkmarked cell. To correct that, write this:
*if ([[marks objectAtIndex:indexPath.row] isEqualToString:#"YES"]) {
[cell setAccessoryType:UITableViewCellAccessoryCheckmark];
}else {
[cell setAccessoryType:UITableViewCellAccessoryNone];*
Out of cell reusing space. That is After:
...
}
//Configure the cell.
just before
*return cell;*
Try this. Here selectedRow is an integer .Assign selectedRow = -1 in viewDidLoad.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
}
cell.selectionStyle = UITableViewCellSelectionStyleNone;
int row = [indexPath row];
cell.accessoryType = (row == selectedRow) ? UITableViewCellAccessoryCheckmark : UITableViewCellAccessoryNone;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
selectedRow = [indexPath row];
[tableView reloadData];
}
check this
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *thisCell = [tableView cellForRowAtIndexPath:indexPath];
if (thisCell.accessoryType == UITableViewCellAccessoryNone) {
thisCell.accessoryType = UITableViewCellAccessoryCheckmark;
}else{
thisCell.accessoryType = UITableViewCellAccessoryNone;
}
}
- (UITableViewCellAccessoryType)tableView:(UITableView *)tableView accessoryTypeForRowWithIndexPath:(NSIndexPath *)indexPath {
//add your own code to set the cell accesory type.
return UITableViewCellAccessoryNone;
}
i faced same issue. for me, solution was adding a single line of code.
cell.accessoryType = UITableViewCellAccessoryNone;
adding the above code after:
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
this solution may not be useful for coder who posted the question, but may help new folks like me who face same issue as raised by the original quesiton.
I'm trying to add checkmarks to items when the user select rows in a table view. However, the view is not refreshed and the checkmarks do no show up:
- (void)tableView:(UITableView *)tv didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell* oldCell = [self tableView:tv cellForRowAtIndexPath:[NSIndexPath indexPathForRow:selectedIndex inSection:0]];
oldCell.accessoryType = UITableViewCellAccessoryNone;
if (indexPath.section == 0) {
selectedIndex = indexPath.row;
}
UITableViewCell* newCell = [self tableView:tv cellForRowAtIndexPath:indexPath];
newCell.accessoryType = UITableViewCellAccessoryCheckmark;
[tv deselectRowAtIndexPath:indexPath animated:NO];
}
What could be a reason for that?
Call cellForRowAtIndexPath directly on the tv object instead of through self to make sure you get a proper cell reference back:
- (void)tableView:(UITableView *)tv didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *oldCell = [tv cellForRowAtIndexPath:[NSIndexPath indexPathForRow:selectedIndex inSection:0]];
oldCell.accessoryType = UITableViewCellAccessoryNone;
if (indexPath.section == 0) {
selectedIndex = indexPath.row;
}
UITableViewCell *newCell = [tv cellForRowAtIndexPath:indexPath];
newCell.accessoryType = UITableViewCellAccessoryCheckmark;
[tv deselectRowAtIndexPath:indexPath animated:NO];
}
Also make sure that in cellForRowAtIndexPath, you have this logic:
...
if (indexPath.row == selectedIndex)
cell.accessoryType = UITableViewCellAccessoryCheckmark;
else
cell.accessoryType = UITableViewCellAccessoryNone;
...
return cell;
otherwise, a checkmark will remain on a cell after it scrolls off the screen and comes back on screen even after you've selected another cell.