Show and Hide a Custom Cell - objective-c

My UITableView has one section, and if all cells are visible there will be a total of 6.
There is only one cell that I would like to be able to show and hide.
Here's an overview:
cell 0 - always shown
cell 1 - always shown
cell 2- always shown
cell 3 - always shown
cell 4 - initially hidden / will show or hide if cell 3 is tapped
cell 5 - always shown
Here's a sample of what I have tried for animating/showing the cell through didSelectRowAtIndexPath. Not sure if I am on the right track, but if someone could take a look and help me see where I have messed up I would greatly appreciate it!
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
if (indexPath.row == 3)
{
if (self.indexPathSelected != indexPath)
{
[tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:self.indexPathSelected.row+1 inSection:self.indexPathSelected.section]].hidden = YES;
[tableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationTop];
[tableView beginUpdates];
[[tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:indexPath.row+1 inSection:indexPath.section]] performSelector:#selector(setHidden:) withObject:NO afterDelay:0.25];
self.indexPathSelected = indexPath;
[tableView endUpdates];
return;
}
}
}
So when I tap on cell 3, it just makes the last cell flicker.

By considering, there will be of total 6 rows in tableview and only one section, for this better u make a mutable array to hold all the objects for ur tableview then use insertRowsAtIndexPaths: withRowAnimation: and deleteRowsAtIndexPaths: withRowAnimation: instead of using selector following code gives the example how to hide and show the tableview cell
mutArray = [[NSMutableArray alloc]initWithObjects:#"cell 1",#"cell 2",#"cell 3",#"cell 4",#"cell 6", nil]; //initially ur array contains only 5 objects notice that "cell 5" is not there this will be hidden
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [mutArray count];
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [self.aTableView dequeueReusableCellWithIdentifier:#"cell"];
if(mutArray.count != 6) //initially only 5 rows are present
{
if(cell == nil)
{
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"cell"];
}
cell.textLabel.text = [mutArray objectAtIndex:indexPath.row];
cell.textLabel.backgroundColor = [UIColor clearColor];
return cell;
}
else //for 5th row it must be a custom cell
{
return [mutArray objectAtIndex:indexPath.row];//becz u are already initilised ur custom cell just return it
}
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
if(indexPath.row == 3)
{
int totalRows = [tableView numberOfRowsInSection:indexPath.section];
[tableView beginUpdates];
if(totalRows == 5)
{
//initilise ur custom cell and add it to datasource array
CustomCell *customCell = [[CustomCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"customCell"];
customCell.textLabel.text = #"cell 5";
[mutArray insertObject:customCell atIndex:4];
[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForItem:indexPath.row + 1 inSection:indexPath.section]] withRowAnimation:UITableViewRowAnimationFade];
}
else
{
[mutArray removeObjectAtIndex:5];
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForItem:indexPath.row + 1 inSection:indexPath.section]] withRowAnimation:UITableViewRowAnimationFade];
}
[tableView endUpdates];
}
}
if all ur cells are custom then dont need to comepare in -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath method
Hope this helps u :)

Related

Expand and Collapse specific row after selected in UITableViewCell

I am trying to implement the expand/collapse table view cell. It's working good for many rows; they can be expanded and collapsed after clicked.
But what happen is when my table view has only one row; when I click it and then all the rest of the rows are expended too even though they are empty.
Here my code:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if(selectedIndex == indexPath.row){
return 100;
}else{
return 44;
}
}
// Display in cell
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *cellIdentifier = #"CommentTableCell";
//-- try to get a reusable cell --
CommentTableCell *cell = (CommentTableCell *) [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
//-- create new cell if no reusable cell is available --
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:cellIdentifier owner:self options:nil];
cell = [nib objectAtIndex:0];
}
VocabularyController *vc;
// Display word from database else display vocabulary when searching
if (tableView != self.strongSearchDisplayController.searchResultsTableView) {
vc = [self.myArray objectAtIndex:indexPath.row];
}else{
vc = [self.filteredArray objectAtIndex:indexPath.row];
}
cell.nameLabel.text = vc.korean;
return cell;
}
// Selected Cell
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if(selectedIndex == indexPath.row){
selectedIndex = -1;
NSIndexPath* rowToReload = [NSIndexPath indexPathForRow:indexPath.row inSection:0];
NSArray* rowsToReload = [NSArray arrayWithObjects:rowToReload, nil];
[tableView beginUpdates];
[tableView reloadRowsAtIndexPaths:rowsToReload withRowAnimation:UITableViewRowAnimationFade];
[tableView endUpdates];
return;
}
if(selectedIndex >= 0){
NSIndexPath *previousPath = [NSIndexPath indexPathForRow:selectedIndex inSection:selectedSection];
selectedIndex = indexPath.row;
[tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:previousPath] withRowAnimation:UITableViewRowAnimationFade];
}
// Finally set the selected index to the new selection and reload it to expand
selectedIndex = indexPath.row;
[tableView beginUpdates];
[tableView endUpdates];
}
// I would like show my screen shot.
How to expand only selected row when there is only one result after search? How to keep the other empty stay the same !
Thank for reading.
I don't think you can change that behavior for a one row table -- the table shows the cell dividers based on the height of that one row. If you don't want this look, then I think you have to set the separatorStyle to UITableViewCellSeparatorStyleNone. You could make a custom cell that has a line at the bottom to mimic a cell separator if want to see a line only at the bottom of filled cells.

How to tell which UITableCells are selected with a check mark in a Multi Select UITableview. Objective C

I have a UITableview and in that TableView I which populates with json data. I have implemented a multi selected tableview code that checks the touched table cell with a checkmark.
My question is how can I tell which of my tableview cells I have selected and how do I put an action to the selected table view cells?
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.json2.count;
}
-(UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"CellIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] ;
}
cell.textLabel.text = self.json2[indexPath.row][#"SurveyName"];
//cell.detailTextLabel.text = self.json1[indexPath.row][#"AssetDesc"];
// Sets the accessory for the cell
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
return cell;
}
- (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;
}
So normally If I were to make a segue from a tableview cell I would do the following:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// Perform segue
[tableView deselectRowAtIndexPath:indexPath animated:YES];
[self performSegueWithIdentifier: #"showSurveyForm" sender:self];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"showSurveyForm"]) {
// NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
CameraViewController *destViewController = segue.destinationViewController;
// Hide bottom tab bar in the detail view
destViewController.hidesBottomBarWhenPushed = YES;
destViewController.surveyQuestionId = self.surveyQuestionIDParsed;
destViewController.jsonTitleforSurvey = self.json2;
destViewController.surveyTitleAssetId = self.assetSurvey;
NSLog(#"Survey ID for Survey: %#", self.surveyQuestionIDParsed);
NSLog(#"Survey name titile: %#", self.json2 );
NSLog(#"Asset ID for Title: %#", self.assetSurvey);
}
else if ([segue.identifier isEqualToString:#"showCameraRoll"]) {
// NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
// Hide bottom tab bar in the detail view
}
else if ([segue.identifier isEqualToString:#"showJsonData"]) {
// NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
}
else if ([segue.identifier isEqualToString:#"testPickerDemo"]) {
// NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
}
}
I would like to make a segue after choosing the multi selected cells in my UItableview.
e.g I make a selection and 2 rows are checked. I would like to capture or see in my nslog which tableview cells were selected so I can do another json call and segue based on the rows that were selected.
I know how to call and parse json and make a segue.
You can modify your -didSelectRowAtIndexPath something like this :
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *thisCell = [tableView cellForRowAtIndexPath:indexPath];
NSString *selStr = [yourSourceArray objectAtIndex:indexPath.row];
---> NSMutableArray *selArray = [[NSMutableArray alloc] init]; //Write this line in viewDidLoad method.
if (thisCell.accessoryType == UITableViewCellAccessoryNone)
{
thisCell.accessoryType = UITableViewCellAccessoryCheckmark;
[selArray addObject:selStr];
}
else
{
thisCell.accessoryType = UITableViewCellAccessoryNone;
[selArray removeObject:selStr];
}
NSLog(#"selArray :: %#",selArray);
}
UPDATE :
It will give you the Array of textLabel's text of Selected Rows. Then you can use it in -yourButtonPressed method
- (IBAction)yourButtonPressed:(id)sender;
{
NSLog(#"selArray :: %#",selArray);
}
GoodLuck !!!

Why won't UITableViewCellAccessoryCheckMark Go Away?

Okay so I am slowly figuring this out. Just one more issue I am having. I am using a string and saying that if the string is equal to the cell text to put a checkmark on it when it loads the tableView.
Here is my code for that:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if ([cell.textLabel.text isEqualToString:transferData]) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
I am then telling it to remove that checkmark and add the checkmarks accordingly when being selected:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
cell.accessoryType = UITableViewCellAccessoryNone;
UITableViewCell *cellCheck = [tableView
cellForRowAtIndexPath:indexPath];
cellCheck.accessoryType = UITableViewCellAccessoryCheckmark;
transferData = cellCheck.textLabel.text;
NSLog(#"%#", transferData);
}
- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell* uncheckCell = [tableView
cellForRowAtIndexPath:indexPath];
uncheckCell.accessoryType = UITableViewCellAccessoryNone;
}
Everything works fine, except when it first loads. For some reason when I select on another cell, the checkmark that is originally loaded with the tableView won't go away. Why is this?
You are making a common mistake.
When selecting the cell, you are setting the state of the check mark directly. What you should be doing is setting the state of the checkmark in the data source and let the table cell configure itself from the data source.
Edited example for an exclusive checked table view
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSArray *changedIndexPaths = nil;
NSIndexPath *currentCheckedIndexPath = [self indexPathOfCurrentCheckedObject];
if (currentCheckedIndexPath && ![currentCheckedIndexPath isEqual:indexPath]) {
// There is currently a checked index path - unselect the data source and
// add it to the changed index array.
[[self.tableData objectAtIndex:currentCheckedIndexPath.row] setChecked:NO];
changedIndexPaths = #[indexPath, currentCheckedIndexPath];
} else{
changedIndexPaths = #[indexPath];
}
[[self.tableData objectAtIndex:indexPath.row] setChecked:YES];
[self.tableView reloadRowsAtIndexPaths:changedIndexPaths withRowAnimation:UITableViewRowAnimationNone];
}
I have a new sample app you can download to see the whole project:
You need:
if (self.selectedPath && [indexPath isEqual:self.selectedPath]) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
} else {
cell.accessoryType = UITableViewCellAccessoryNone;
}
Cells get reused. If you conditionally set any cell attribute, you must always have the 'else' part to reset the attribute.
Edit: With the above change in your cellForRowAtIndexPath: method, do the following in your didSelectRowAtIndexPath: method:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSIndexPath *oldSelection = self.selectedPath;
if (self.selectedPath) {
UITableViewCell* uncheckCell = [tableView cellForRowAtIndexPath:self.selectedPath];
uncheckCell.accessoryType = UITableViewCellAccessoryNone;
self.selectedPath = nil;
}
if (oldSelection == nil || ![indexPath isEqual:oldSelection]) {
UITableViewCell* checkCell = [tableView cellForRowAtIndexPath:indexPath];
checkCell.accessoryType = UITableViewCellAccessoryCheckmark;
self.selectedPath = indexPath;
}
[tableView deselectRowAtIndexPath:indexPath];
}
And get rid of the didDeselectRowAtIndexPath: method.
And of course you need the selectedPath property of type NSIndexPath *.
This code lets you pick 0 or 1 row.

indexPathForSelectedRow always returns 0,0 irrespective of the row selected

I would like to replace the cell that is touched by a custom cell. I do this by calling reloadRowsAtIndexPaths
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationNone];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"Row selected: %d", [tableView indexPathForSelectedRow] row]);
NSLog(#"Section selected: %d", [tableView indexPathForSelectedRow] section]);
//return a custom cell for the row selected
}
When I try to access/log the indexPathForSelectedRow from within the cellForRowAtIndexPath, it returns 0,0 no matter which cell I select. Why is this?
Your call to reloadRowsAtIndexPaths: will cause the table view to reload the given cells and therefore cause the table to no longer have a selected row at that position. The cellforRowAtIndexPath method is a request from the data source to provide a row for the given index path. If you need to determine if a cell was selected prior to the request, you could store the indexPath of the selected row in a member. Then check the member in your cellForIndexPathMethod.
The following code sample assumes you are using ARC for memory management.
- (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];
}
cell.textLabel.text = [NSString stringWithFormat:#"Cell %d_%d", indexPath.section, indexPath.row];
// Configure the cell...
if(selectedIndexPath != nil) {
NSLog(#"Selected section:%d row:%d", selectedIndexPath.section, selectedIndexPath.row);
//TODO:Provide a custom cell for the selected one.
//Set the selectedIndexPath to nil now that it has been handled
selectedIndexPath = nil;
}
return cell;
}
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
//Store the selected indexPath
selectedIndexPath = indexPath;
[tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationNone];
}

iPhone's UITableViewCellAccessoryCheckMark

I have an issue in creating a CheckMarkAccessoryView in the UITableView.When i select a row in the table i can get a checked mark for that row,but randomly some other rows in the table also gets the check mark.I want only that cell to get the check mark.How can i do this?I am coding for an exclusive list.The following is the code which i have used.
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if(tableView==tableView1)
{
return […arraycount1…. ];
}
else
{
return […arraycount2…. ];
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
}
else
{
UIView* subview;
while ((subview = [[[cell contentView] subviews] lastObject]) != nil)
[subview removeFromSuperview];
}
if(tableView == tableView1)
{
cell.textLabel.text=[array1 objectAtIndex:indexPath.row];
}
else //Tableview2
{
cell.textLabel.text=[array2 objectAtIndex:indexPath.row];
}
cell.textLabel.font=[UIFont fontWithName:#"Georgia" size:20];
cell.textLabel.textAlignment=UITextAlignmentLeft;
[cell setSelectedBackgroundView:border];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *oldCell = [tableView cellForRowAtIndexPath:lastindex];
if (oldCell.accessoryType == UITableViewCellAccessoryCheckmark);
{
oldCell.accessoryType = UITableViewCellAccessoryNone;
}
UITableViewCell *newCell = [tableView cellForRowAtIndexPath:indexPath];
if (newCell.accessoryType == UITableViewCellAccessoryNone)
{
newCell.accessoryType = UITableViewCellAccessoryCheckmark;
}
}
Kindly correct me where i am going wrong.
Thanks in advance for all the experts.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
for (id algoPath in [tableView indexPathsForVisibleRows])
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:algoPath];
cell.accessoryType = UITableViewCellAccessoryNone;
if(algoPath == indexPath)
{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
}
}
i tried different things out, nothing worked properly. now i'm iterating over all indices, setting all Accessories to None, and then the current one to accessoryCheckmark. not the cleanest approach but working.
UITableView reuses cell objects as you scroll the table, so setting the cell to show a checkmark means that it will also have a checkmark when it's reused
You need to store the state of each row in an array separate from the cells (or if you only need one cell at a time checked, just store an index somewhere), and then read from that array and set the appropriate accessoryType in the cellForRowAtIndexPath: method.
(alternatively you could simply disable cell reuse by removing the dequeueReusableCellWithIdentifier: call, but that's bad for performance if you have a long list to scroll)
The two if statement cancel each other, just add else like the following :
UITableViewCell *oldCell = [tableView cellForRowAtIndexPath:lastindex];
if (oldCell.accessoryType == UITableViewCellAccessoryCheckmark)
{
oldCell.accessoryType = UITableViewCellAccessoryNone;
}
else
{
UITableViewCell *newCell = [tableView cellForRowAtIndexPath:indexPath];
if (newCell.accessoryType == UITableViewCellAccessoryNone)
{
newCell.accessoryType = UITableViewCellAccessoryCheckmark;
}
}
I think you are looking for these methods!
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.section!=0) {
[tableView cellForRowAtIndexPath:indexPath].accessoryType = UITableViewCellAccessoryCheckmark;
}
}
//didDeselect method in table view for removing previous checkmark
-(void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.section!=0)
{
[tableView cellForRowAtIndexPath:indexPath].accessoryType = UITableViewCellAccessoryNone;
}
}