So I have a deadline coming up for this project and I've been working hard on it and so I'm pretty tired right now. I don't know if I'm just being stupid and blind to what I'm doing wrong but I have a problem that I need help with.
So, I'm trying to implement a sort of "expanding tableview setup" (like in IOS 7 calendar where you tap on the start and end dates and a cell pops in with a date picker). I have two different cells that can be displayed under a tapped cell. It works perfectly except for the actual cell, when I insert a row the wrong cell is displayed. I'll give some context... I have two cells in section 0, when you tap on the first cell it inserts a cell below it that should be a picker cell. Instead it inserts the same call as in row 1 of the unmodified tableview.
Here is the relevant code:
#interface AddMealTableViewController ()
#property (nonatomic) BOOL datePickerEnabled;
#property (nonatomic) BOOL pickerEnabled;
#property (nonatomic, strong) NSIndexPath *datePickerIndexPath;
#property (nonatomic, strong) NSIndexPath *pickerIndexPath;
#end
#implementation AddMealTableViewController
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 2;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
switch (section) {
case 0:
return 2 + (self.datePickerEnabled) + (self.pickerEnabled);
break;
default:
return self.mealComponents.count;
break;
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
switch (indexPath.section) {
case 0:
{
if (indexPath.row == 1) {
TimeCell *cell = [tableView dequeueReusableCellWithIdentifier:#"TimeCell"];
cell.timeLabel.text = #"Now";
cell.mealTypeLabel.text = self.selectedMealType;
return cell;
}
else if (indexPath == self.datePickerIndexPath) {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"DateCell"];
return cell;
}
else if (indexPath == self.pickerIndexPath) {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"PickerCell"];
return cell;
}
else {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"MealTypeCell"];
cell.textLabel.text = #"Meal Type";
cell.detailTextLabel.text = self.selectedMealType;
return cell;
}
break;
}
default:
{
ComponentCell *cell = [tableView dequeueReusableCellWithIdentifier:#"ComponentCell"];
if (!cell) {
cell = [ComponentCell new];
}
MealComponent *mc = self.mealComponents[indexPath.row];
[cell setUpWithComponent:mc];
return cell;
break;
}
}
return nil;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.section == 0) {
if (indexPath == self.datePickerIndexPath || indexPath == self.pickerIndexPath) {
return 200;
}
return self.tableView.rowHeight;
}
return 70;
}
- (void)toggleDatePickerForSelectedIndexPath:(NSIndexPath *)indexPath
{
[self.tableView beginUpdates];
NSArray *indexPaths = #[[NSIndexPath indexPathForRow:indexPath.row + 1 inSection:0]];
if (self.datePickerEnabled)
{
self.datePickerEnabled = NO;
self.datePickerIndexPath = nil;
[self.tableView deleteRowsAtIndexPaths:indexPaths
withRowAnimation:UITableViewRowAnimationFade];
}
else
{
self.datePickerIndexPath = indexPaths.lastObject;
self.datePickerEnabled = YES;
[self.tableView insertRowsAtIndexPaths:indexPaths
withRowAnimation:UITableViewRowAnimationFade];
}
[self.tableView endUpdates];
}
- (void)togglePickerForSelectedIndexPath:(NSIndexPath *)indexPath
{
[self.tableView beginUpdates];
NSArray *indexPaths = #[[NSIndexPath indexPathForRow:indexPath.row + 1 inSection:0]];
if (self.pickerEnabled)
{
self.pickerEnabled = NO;
self.pickerIndexPath = nil;
[self.tableView deleteRowsAtIndexPaths:indexPaths
withRowAnimation:UITableViewRowAnimationFade];
}
else
{
self.pickerIndexPath = indexPaths.lastObject;
self.pickerEnabled = YES;
[self.tableView insertRowsAtIndexPaths:indexPaths
withRowAnimation:UITableViewRowAnimationFade];
}
[self.tableView endUpdates];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.section == 0) {
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
if ([cell.reuseIdentifier isEqual: #"TimeCell"]) {
[self toggleDatePickerForSelectedIndexPath:indexPath];
}
else if ([cell.reuseIdentifier isEqual: #"MealTypeCell"]) {
[self togglePickerForSelectedIndexPath:indexPath];
}
}
}
Any ideas? I really can't seem to put my finger on it.
why don't you change the height of date picker cell from 0 to 200 instead insert (or delete) the date picker cell. I think this is more simple.(This is what I'm used to implement that)
when [tableView didSelectRowAtIndexPath:] is called, you just call [tableView reloadRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic] to update cell.
You can managed the height of cell in [tableView heightForRowAtIndexPath:] you already know.
[edited]
I examine your code again.
change else if (indexPath == self.datePickefIndexPath) to else if([indexPath isEqual:self.datePickerIndexPath]) in [tableView:cellForRowAtIndexPath:]
There're many ways to handle this kind of things. You really don't need to insert or delete cell, just modify the cell height from 0 to the proper height. To do this, you can set a flag to check whether the cell's expanded or not.
Related
Here i am trying to create expand/collapse table row.it is working fine with this code in didSelectRowAtIndexPath only for 1 section:
if (selectedIndex == indexPath.row) {
selectedIndex = -1;
[tableView reloadRowsAtIndexPaths:[NSArray arrayWithObjects:indexPath, nil]withRowAnimation:UITableViewRowAnimationFade];
return;
}
//for table view collapse
if (selectedIndex != -1) {
NSIndexPath *prePath = [NSIndexPath indexPathForRow:selectedIndex inSection:0];
selectedIndex = (int)indexPath.row;
[tableView reloadRowsAtIndexPaths:[NSArray arrayWithObjects:prePath, nil]withRowAnimation:UITableViewRowAnimationFade];
}
//for non selection
selectedIndex = (int)indexPath.row;
[tableView reloadRowsAtIndexPaths:[NSArray arrayWithObjects:indexPath, nil]withRowAnimation:UITableViewRowAnimationFade];
through this code i can expand and collapse table row but if and only if for 1 section in table but when multiple section comes it is expanding each sections particular row.so when i click on section 0's 1st row it is going to open all section's 1st row.
How to get rid of this situation?
Tapping on particular section button you can change number of rows.
In section view you have added one button for all section which has common method while tapping.
In tapping method you have to just change bool variable value for particular section
ex.. if sender tag you initials with section number.
So For Section 0 button is taped then in tapping method
if sender.tag == 0
{
if section0tag
{
section0tag = false
}
else
{
section0tag = true
}
table.reload() ..//Which call number of rows at section data source method
}
For number of rowsatSection method data source method
if section == 0
{
if section0tag
{
return 5 //Expanding rows
}
else
{
return 0 //collapsing rows
}
}
Try this method just reload tableview (i.e rOne,rTwo, etc are the bool value):
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (section == 0) {
return rOne ? oneRoundType.count : 0 ;
}else if (section ==1) {
return rTwo ? twoRoundType.count : 0 ;
}else if (section ==2) {
return rThree ? threeRoundType.count : 0 ;
}else if (section ==3) {
return rFour ? fourRoundType.count : 0 ;
}else if (section ==4) {
return rFive ? fiveRoundType.count : 0 ;
}
return 0;
}
Please try below code:
Global declaration of sectionIndexToBeExpanded as int to check whether it is expanded or not
int sectionIndexToBeExpanded;
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
//Assign value 100 to sectionIndexToBeExpanded, if you do not want row expanded
sectionIndexToBeExpanded = 100;
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [yourArray count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (sectionIndexToBeExpanded==100) //If not expanded
{
return 1;
}
else if (sectionIndexToBeExpanded==section) //If section expand add one more row
{
return 2;
}
else
return 1;
}
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.row==0)
{
if (sectionIndexToBeExpanded==100) //If section not expanded set value of sectionIndexToBeExpanded to 100
{
UITableViewCell *cell=(UITableViewCell*)[tableView cellForRowAtIndexPath:indexPath];
[tableView beginUpdates];
[tableView insertRowsAtIndexPaths:#[[NSIndexPath indexPathForRow:indexPath.row+1 inSection:indexPath.section]] withRowAnimation:UITableViewRowAnimationRight];
sectionIndexToBeExpanded=(int)indexPath.section;
[tableView endUpdates];
}
else if (sectionIndexToBeExpanded==indexPath.section) // If Section is already expanded at indexpath then collapse ie. delete row
{
UITableViewCell *cell=(UITableViewCell*)[tableView cellForRowAtIndexPath:indexPath];
[tableView beginUpdates];
[tableView deleteRowsAtIndexPaths:#[[NSIndexPath indexPathForRow:indexPath.row+1 inSection:sectionIndexToBeExpanded]] withRowAnimation:UITableViewRowAnimationLeft];
sectionIndexToBeExpanded=100; //Set section to not expanded
[tableView endUpdates];
}
else //Expand section
{
UITableViewCell *cell=(UITableViewCell*)[tableView cellForRowAtIndexPath:indexPath];
[tableView beginUpdates];
[tableView deleteRowsAtIndexPaths:#[[NSIndexPath indexPathForRow:indexPath.row+1 inSection:sectionIndexToBeExpanded]] withRowAnimation:UITableViewRowAnimationLeft];
//set value of expanded section to sectionIndexToBeExpanded
sectionIndexToBeExpanded=(int)indexPath.section;
[tableView insertRowsAtIndexPaths:#[[NSIndexPath indexPathForRow:indexPath.row+1 inSection:indexPath.section]] withRowAnimation:UITableViewRowAnimationLeft];
[tableView endUpdates];
}
}
}
-(CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 44;
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return UITableViewAutomaticDimension;
}
I am using this in my app and i am create two identifiers for UITableview one is "normal cell" and another one is "expended cell" which will show when someone tap on a "normal cell". my problem is this that I can not manage heights of both cells separately for example I want normal cell height to be 120 and extended cell is to be 60. But if I change height in heightForRowAtIndexPath then both cells showing same height. here is my code.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
FSParallaxTableViewCell *cell = nil;
static NSString *cellIdentifier = nil;
if ([indexPath isEqual:self.expandedIndexPath]) {
cellIdentifier = #"ExpandedCell";
}
else {
cellIdentifier = #"NormalCell";
}
cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];
if (cell == nil) {
cell = [[FSParallaxTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
if ([[cell reuseIdentifier] isEqualToString:#"ExpandedCell"]) {
cell.contentView.backgroundColor = [UIColor grayColor];
}
if ([[cell reuseIdentifier] isEqualToString:#"NormalCell"]) {
[cell.cellImageView sd_setImageWithURL:[NSURL URLWithString:[[rssOutputData objectAtIndex:indexPath.row]xmllink]]
placeholderImage:[UIImage imageNamed:#"placeholder"] options:indexPath.row == 0 ? SDWebImageRefreshCached : 0];
cell.clipsToBounds = YES;
}
return cell;
}
- (void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// disable touch on expanded cell
UITableViewCell *cell = [self.theTableView cellForRowAtIndexPath:indexPath];
if ([[cell reuseIdentifier] isEqualToString:#"ExpandedCell"]) {
return;
}
// deselect row
[tableView deselectRowAtIndexPath:indexPath
animated:NO];
// get the actual index path
indexPath = [self actualIndexPathForTappedIndexPath:indexPath];
// save the expanded cell to delete it later
NSIndexPath *theExpandedIndexPath = self.expandedIndexPath;
// same row tapped twice - get rid of the expanded cell
if ([indexPath isEqual:self.expandingIndexPath]) {
self.expandingIndexPath = nil;
self.expandedIndexPath = nil;
}
// add the expanded cell
else {
self.expandingIndexPath = indexPath;
self.expandedIndexPath = [NSIndexPath indexPathForRow:[indexPath row] + 1
inSection:[indexPath section]];
}
[tableView beginUpdates];
if (theExpandedIndexPath) {
[theTableView deleteRowsAtIndexPaths:#[theExpandedIndexPath]
withRowAnimation:UITableViewRowAnimationNone];
}
if (self.expandedIndexPath) {
[theTableView insertRowsAtIndexPaths:#[self.expandedIndexPath]
withRowAnimation:UITableViewRowAnimationNone];
}
[tableView endUpdates];
// scroll to the expanded cell
[self.theTableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionMiddle
animated:YES];
}
can anyone please help me resolving this issue I want to set height for both cells separately.
add below code in heightForAtIndexpath method
if ([indexPath isEqual:self.expandedIndexPath]) {
return 60.0;
}
else
return 120.0f;
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];
}
if ([[cell reuseIdentifier] isEqualToString:#"ExpandedCell"]) {
return 60;
}
if ([[cell reuseIdentifier] isEqualToString:#"NormalCell"]) {
return 120;
}
}
You have to set the height of table view cell separately. you can set the height separately according as the row.In following code i have set the 1st row height 35, 2nd row height 70 and rest of the row will have height 65.
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
switch (indexPath.row)
{
case 0:
return 35;
break;
case 1:
return 70;
break;
default:
return 65;
break;
}
}
I'm seeing a weird effect when inserting/deleting a UITableViewCell in a UITableView with animation (UITableViewRowAnimationTop).
The animation glitch happens when the cell to insert is much bigger than the cell above.
This video shows the glitch in the simulator, yellow cell appears suddenly out of no where when it's supposed to slide from top.
Here is the Xcode project from the video.
Bellow is the cell insertion/animation code.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 2 + self.thirdCellVisible;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:NO];
if (indexPath.row == 1)
{
if (self.thirdCellVisible)
{
self.thirdCellVisible = !self.thirdCellVisible;
[tableView deleteRowsAtIndexPaths:#[self.thirdCellIndexPath]
withRowAnimation:UITableViewRowAnimationTop];
}
else
{
self.thirdCellVisible = !self.thirdCellVisible;
[tableView insertRowsAtIndexPaths:#[self.thirdCellIndexPath]
withRowAnimation:UITableViewRowAnimationTop];
}
}
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.row == self.thirdCellIndexPath.row)
{
return 100.0f;
}
return 44.0f;
}
You will have to call
[tableView beginUpdates]
and
[tableView endUpdates]
before and after calling insert/delete methods as below :
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 2 + self.thirdCellVisible;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:NO];
if (indexPath.row == 1)
{
if (self.thirdCellVisible)
{
self.thirdCellVisible = !self.thirdCellVisible;
[self.tableView beginUpdates];
[tableView deleteRowsAtIndexPaths:#[self.thirdCellIndexPath]
withRowAnimation:UITableViewRowAnimationTop];
[self.tableView endUpdates];
}
else
{
self.thirdCellVisible = !self.thirdCellVisible;
[self.tableView beginUpdates];
[tableView insertRowsAtIndexPaths:#[self.thirdCellIndexPath]
withRowAnimation:UITableViewRowAnimationTop];
[self.tableView endUpdates];
}
}
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.row == self.thirdCellIndexPath.row)
{
return 100.0f;
}
return 44.0f;
}
According to Apple here:
To animate a batch insertion, deletion, and reloading of rows and
sections, call the corresponding methods within an animation block
defined by successive calls to beginUpdates and endUpdates. If you
don’t call the insertion, deletion, and reloading methods within this
block, row and section indexes may be invalid. Calls to beginUpdates
and endUpdates can be nested; all indexes are treated as if there were
only the outer update block.
At the conclusion of a block—that is, after endUpdates returns—the
table view queries its data source and delegate as usual for row and
section data. Thus the collection objects backing the table view
should be updated to reflect the new or removed rows or sections.
You will have to call [tableView beginUpdates] and [tableView endUpdates] before and after calling insert/delete methods respectively.
An example is provided by Apple on the above link.
Note: If your array and table view items are out of sync, without the begin/end calls an exception will be thrown.
Suggestion: Try first withRowAnimation:UITableViewRowAnimationAutomatic
Here is the link of video of my working code: https://dl.dropboxusercontent.com/u/30316681/480.mov
Below is my working code:
#interface ViewController ()
#property (nonatomic, readwrite) BOOL thirdCellVisible;
#property (nonatomic, strong) NSIndexPath *thirdCellIndexPath;
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.thirdCellIndexPath = [NSIndexPath indexPathForRow:2 inSection:0];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 2 + self.thirdCellVisible;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.row == self.thirdCellIndexPath.row)
{
return 100.0f;
}
return 44.0f;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:NO];
if (indexPath.row == 1)
{
if (self.thirdCellVisible)
{
self.thirdCellVisible = !self.thirdCellVisible;
[tableView deleteRowsAtIndexPaths:#[self.thirdCellIndexPath]
withRowAnimation:UITableViewRowAnimationTop];
}
else
{
self.thirdCellVisible = !self.thirdCellVisible;
[tableView insertRowsAtIndexPaths:#[self.thirdCellIndexPath]
withRowAnimation:UITableViewRowAnimationTop];
}
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellId = #"id";
UITableViewCell *cell = [tableView dequeueReusableHeaderFooterViewWithIdentifier:cellId];
if(cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellId];
}
NSString *cellTitle = [NSString stringWithFormat:#"Cell %ld", (long)indexPath.row];
cell.textLabel.text = cellTitle;
if(indexPath.row == 2)
cell.backgroundColor = [UIColor yellowColor];
else
cell.backgroundColor = [UIColor clearColor];
return cell;
}
#end
Use [tableView beginUpdates] and [tableView endUpdates] as follow
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:NO];
if (indexPath.row == 1)
{
if (self.thirdCellVisible)
{
self.thirdCellVisible = !self.thirdCellVisible;
[self.tableView beginUpdates];
[tableView deleteRowsAtIndexPaths:#[self.thirdCellIndexPath]
withRowAnimation:UITableViewRowAnimationTop];
[self.tableView endUpdates];
}
else
{
self.thirdCellVisible = !self.thirdCellVisible;
[self.tableView beginUpdates];
[tableView insertRowsAtIndexPaths:#[self.thirdCellIndexPath]
withRowAnimation:UITableViewRowAnimationTop];
[self.tableView endUpdates];
}
}
}
Suppose there is Custom Cell A & B of different Height.
Custom Cell A is loaded Default on UITableView. When User will Select Cell A it will remove that Cell and Add Cell B to that Position and vise versa. It will do the animation of re-sizing in Accordion style.
To do this, you should have a property (or key if using a dictionary) in your data array to keep track of what cell you want at each indexPath, and use an if-else statement in cellFroRowAtIndexPath to dequeue the correct cell. In didSelectRowAtIndexPath, you would check that property, set it to the opposite one, and then reload the table. You would also need to implement heightForRowAtIndexPath, and check that same property to determine which height to return.
After Edit:
If you just need to keep track of one selected cell, then create a property (I call it selectedPath) to hold that value and check it in heightForRowAtIndexPath and cellForRowAtIndexPath. I created two cells in the storyboard, one a simple UITableViewCell and the other a custom cell of class RDCell. I'm not sure if this gives the animation you want, but give it a try and see if it's close:
#import "TableController.h"
#import "RDCell.h"
#interface TableController ()
#property (strong,nonatomic) NSArray *theData;
#property (nonatomic) NSIndexPath *selectedPath;
#end
#implementation TableController
- (void)viewDidLoad {
[super viewDidLoad];
self.theData = #[#"One",#"Two",#"Three",#"Four",#"Five",#"Six",#"Seven",#"Eight"];
self.selectedPath = [NSIndexPath indexPathForRow:-1 inSection:0];
[self.tableView reloadData];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.theData.count;
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
if ([self.selectedPath isEqual:indexPath]) {
return 90;
}else{
return 44;
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if ([self.selectedPath isEqual:indexPath]) {
RDCell *cell = [tableView dequeueReusableCellWithIdentifier:#"RDCell" forIndexPath:indexPath];
cell.label.text = self.theData[indexPath.row];
return cell;
}else{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
cell.textLabel.text = self.theData[indexPath.row];
return cell;
}
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
NSIndexPath *oldPath = self.selectedPath;
self.selectedPath = indexPath;
[self.tableView reloadRowsAtIndexPaths:#[indexPath,oldPath] withRowAnimation:UITableViewRowAnimationAutomatic];
}
**Got this amazing Solution, its working great...**
#implementation NetworkCentreTable
{
NSMutableArray *arr;
BOOL chk;
int onSelectCount;
NSIndexPath *onSelectTrack;
}
- (void)viewDidLoad
{
[super viewDidLoad];
arr=[[NSMutableArray alloc] initWithObjects:#"1",#"1",#"1",#"1",#"1",#"1",#"1",#"1",#"1",nil];
onSelectCount=0;
static NSString *CellIdentifier1 = #"NetworkCell2";
UINib *nib = [UINib nibWithNibName:#"NetworkCentreCellBig" bundle:nil];
[self.tblNetworkCentre registerNib:nib forCellReuseIdentifier:CellIdentifier1];
}
#pragma mark -
#pragma mark Custom Network TableView delegate and Datasource
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return [arr count];
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return 1;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *CellIdentifier1 = #"NetworkCentreCell";
static NSString *CellIdentifier2 = #"NetworkCentreCellBig";
if(self.selectedRowIndex && indexPath.row == self.selectedRowIndex.integerValue)
{
NetworkCentreCell *cell = (NetworkCentreCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier2];
UIViewController *controller=[[UIViewController alloc] initWithNibName:CellIdentifier2 bundle:nil];
cell=(NetworkCentreCell *)controller.view;
return cell;
}
else
{
NetworkCentreCell *cell = (NetworkCentreCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier1];
UIViewController *controller=[[UIViewController alloc] initWithNibName:CellIdentifier1 bundle:nil];
cell=(NetworkCentreCell *)controller.view;
return cell;
}
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
onSelectCount++;
NSLog(#"num=%d",onSelectCount);
self.selectedIndexPath = indexPath;
[tableView reloadRowsAtIndexPaths:#[indexPath] withRowAnimation: UITableViewRowAnimationNone];
self.selectedRowIndex = [NSNumber numberWithInteger:indexPath.row];
[self.tblNetworkCentre deselectRowAtIndexPath:indexPath animated:YES];
//First we check if a cell is already expanded.
//If it is we want to minimize make sure it is reloaded to minimize it back
if( onSelectCount==1 )
{
[tableView beginUpdates];
NSIndexPath *previousPath = [NSIndexPath indexPathForRow:self.selectedRowIndex.integerValue inSection:0];
self.selectedRowIndex = [NSNumber numberWithInteger:indexPath.row];
onSelectTrack=indexPath;
[tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:previousPath] withRowAnimation:UITableViewRowAnimationFade];
[tableView endUpdates];
}
if(onSelectTrack.row!=indexPath.row)
{
[tableView beginUpdates];
[tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:onSelectTrack] withRowAnimation:UITableViewRowAnimationFade];
[tableView endUpdates];
onSelectTrack=indexPath;
onSelectCount=0;
[self tableView:tableView didSelectRowAtIndexPath:onSelectTrack];
}
if(self.selectedRowIndex.integerValue == indexPath.row && onSelectCount==2)
{
[tableView beginUpdates];
self.selectedRowIndex = [NSNumber numberWithInteger:-1];
[tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
onSelectCount=0;
[tableView endUpdates];
}
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
if(self.selectedRowIndex && indexPath.row == self.selectedRowIndex.integerValue)
{
return 280;
}else{
return 85;
}
}
You can call [yourTableview reloadData] in didSelectRowAtIndexPath method.
Then in numberOfRowsInSection give a new count. In heightForRowAtIndexpath specify the custom heights.
In cellForRowAtIndexpath add custom cells.
I have searched and search and i just can´t seem to find an answer to my problem. I have a dynamic tableview with 3 rows (each row is a section) and a edit button at the top right of the tableview. each time the user taps edit it has to be possible to add or delete a row. Everything works except the part when the + button is taped to ad a new row. This is my code:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 3;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
int count = [myarray count];
if (myarray != nil) count ++;
return count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
id cell;
switch(indexPath.section) {
case 0:
if(indexPath.row==0) {
static NSString *cellType1 = #"cellType1";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellType1];
return cell;
}
break;
case 1:
if(indexPath.row==0) {
static NSString *cellType2= #"cellType2";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellType2];
return cell;
}
break;
case 2:
if(indexPath.row==0) {
static NSString *cellType3= #"cellType3";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellType3];
return cell;
}
break;
default:
break;
}
return cell;
}
- (IBAction) EditTable:(id)sender
{
if(self.editing)
{
[super setEditing:NO animated:NO];
[Table setEditing:NO animated:NO];
[Table reloadData];
[self.navigationItem.rightBarButtonItem setTitle:#"Edit"];
[self.navigationItem.rightBarButtonItem setStyle:UIBarButtonItemStylePlain];
}
else
{
[super setEditing:YES animated:YES];
[Table setEditing:YES animated:YES];
[Table reloadData];
[self.navigationItem.rightBarButtonItem setTitle:#"Ok"];
[self.navigationItem.rightBarButtonItem setStyle:UIBarButtonItemStyleDone];
}
}
- (UITableViewCellEditingStyle)tableView:(UITableView *)aTableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (self.editing == NO || !indexPath) return UITableViewCellEditingStyleNone;
if (self.editing && indexPath.row == ([myarray count]))
{
return UITableViewCellEditingStyleInsert;
} else
{
return UITableViewCellEditingStyleDelete;
}
return UITableViewCellEditingStyleNone;
}
- (void)tableView:(UITableView *)TableView commitEditingStyle: (UITableViewCellEditingStyle)editingStyle
forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete)
{
[myarray removeObjectAtIndex:indexPath.row];
[Table reloadData];
} else if (editingStyle == UITableViewCellEditingStyleInsert)
{
switch(indexPath.section) {
case 0:
if(indexPath.row==0) {
static NSString *cellType1 = #"cellType1";
UITableViewCell *cell = [TableView dequeueReusableCellWithIdentifier:cellType1];
[arry insertObject:cell atIndex:[myarray count]];
[Table reloadData];
}
break;
case 1:
if(indexPath.row==0) {
static NSString *cellType2= #"cellType2";
UITableViewCell *cell = [TableView dequeueReusableCellWithIdentifier:cellType2];
[arry insertObject:cell atIndex:[myarray count]];
}
break;
case 2:
if(indexPath.row==0) {
static NSString *cellType3= #"cellType3";
UITableViewCell *cell = [TableView dequeueReusableCellWithIdentifier:cellType3];
[arry insertObject:cell atIndex:[myarray count]];
}
break;
default:
break;
}
}
As i said before, everything works until i press the + button (that appears on the left side when the edit button is pressed) to add a new row. Then it shows an error: 'UITableView dataSource must return a cell from tableView:cellForRowAtIndexPath.
What am i doing wrong? any help would be most appreciated.
First off, you never actually +alloc or -init a cell, so -cellForRowAtIndexPath: is most likely returning nil (-dequeueReusableCellWithIdentifier: doesn't cut it).
Second off, comparing indexPath.row to [myarray count] will never be true, because arrays and tables may be zero-based, but their counts aren't.