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];
}
}
}
Related
Here is my screen and code i have attached below.can any one give idea how to implement the screen thanks in advance..in my header section i need show only the tableview cell.........................................
[1]: http://i.stack.imgur.com/EVlQs.png
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection: (NSInteger)section
{
return [arr count];
}
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *cellidentifier =#"cell";
MyOrderCell *cell = (MyOrderCell *)[tableView dequeueReusableCellWithIdentifier:cellidentifier];
/********** If the section supposed to be closed *******************/
if(cell==nil)
{
cell = [[MyOrderCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellidentifier];
}
if (selectedindex==indexPath.row) {
// do expanded stuff here
cell.lblcope.text=[[pendentsdata objectAtIndex:indexPath.row]valueForKey:#"pendents"];
cell.lblcopieces.text=[[pendentsdata objectAtIndex:indexPath.row]valueForKey:#"copiece"];
cell.lblconum.text=[[pendentsdata objectAtIndex:indexPath.row]valueForKey:#"conum"];
cell.lblcodate.text=[[pendentsdata objectAtIndex:indexPath.row]valueForKey:#"codate"];
cell.lblcoenddate.text=[[pendentsdata objectAtIndex:indexPath.row]valueForKey:#"coenddate"];
cell.lbltotl.text=[[pendentsdata objectAtIndex:indexPath.row]valueForKey:#"cototal"];
cell.accessoryType=UITableViewCellAccessoryDisclosureIndicator;
}else
{
// do closed stuff here
cell.lblpendnts.text=[arr objectAtIndex:indexPath.row];
cell.lblpieces.text=[arrpieces objectAtIndex:indexPath.row];
cell.lblnum.text=[arrnum objectAtIndex:indexPath.row];
cell.lbldate.text=[arrdate objectAtIndex:indexPath.row];
cell.lblenddate.text=[arrenddate objectAtIndex:indexPath.row];
cell.lbltotl.text=[arrttl objectAtIndex:indexPath.row];
cell.accessoryType=UITableViewCellAccessoryDisclosureIndicator;
}
return cell;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (selectedindex==indexPath.row) {
selectedindex=-1;
[tbldata reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
return;
}
if (selectedindex !=-1) {
NSIndexPath *prevpath=[NSIndexPath indexPathForRow:selectedindex inSection:0];
selectedindex=indexPath.row;
[tbldata reloadRowsAtIndexPaths:[NSArray arrayWithObject:prevpath] withRowAnimation:UITableViewRowAnimationFade];
}
selectedindex=indexPath.row;
[tbldata reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (selectedindex==indexPath.row) {
return 100;
}else
{
return 50;
}
}
You can use https://github.com/iSofTom/STCollapseTableView
I have used this in a project. The code written is very clean, so you can also easily customise it to cater your specific needs if any.
You can use SubTable, a third party subclass of UITableView. Besides same questions as yours are below, check them out:
How to create an Accordion with UItableview under a UItableview?
Accordion table cell - for expand and collapse ios
Indeed Burak, or take tutorial...
an example: https://blog.pivotal.io/labs/labs/expandable-uitableviewcells
I have a UITableView. I use this code to resize the selected row:
-(void) viewWillAppear:(BOOL)animated {
....
[self.tableView registerNib:[UINib nibWithNibName:#"ICSceneDetailViewTableViewCell" bundle:[NSBundle mainBundle]] forCellReuseIdentifier:IC_CELL_SCENE_EDITOR_CELL];
...
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
-(int) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (tableView == nil)
return 0;
if (self.scenes != nil) {
return self.scenes.count;
}
return 0;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
ICSceneDetailViewTableViewCell *cell = (ICSceneDetailViewTableViewCell*)[tableView dequeueReusableCellWithIdentifier:IC_CELL_SCENE_EDITOR_CELL forIndexPath:indexPath];
if (cell == nil) {
cell = [[ICSceneDetailViewTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:IC_CELL_SCENE_EDITOR_CELL];
}
ICScene *scene = [self.scenes objectAtIndex:[indexPath row]];
[cell.titleTextField setText:scene.title];
return cell;
}
-(void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
self.selectedRow = indexPath.row;
[self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObjects:indexPath, nil] withRowAnimation:UITableViewRowAnimationNone];
[self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionTop animated:NO];
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
if ([indexPath row] == self.selectedRow) {
return 250;
}
if (IS_IPAD) {
return 80;
}
else {
return 40;
}
}
-(UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath {
return UITableViewCellEditingStyleNone;
}
BUT, after selecting any row (name it A, and A become resized):
if I drag another row (name it B) then randomly other rows disappears (except A).
if I scroll tableview and back to drag on same row (B) then, again randomly, other(s) cell(s) disappear(s), but not always the same(s).
if I comment heightForRowAtIndexPath then drag behavior is normal, but row can't be resized :(
I already searched many similar answers (adjusting selectedBackgroundView on cell, backgroundView cell, drawRect on cell, etc) but no one solution/workaround works for this simple (i think) code.
Thanks in advance :)
Yeh, answering my own question.
I found an alternative to resize selected UITableViewCell without calling to reloadRowsAtIndexPaths.
Replacing reloadRowsAtIndexPaths with:
[self.tableView beginUpdates];
[self.tableView endUpdates];
refreshes visible rows without calling cellForRowAtIndexPath. Imho the problem where dequeuing cells on every row being reloaded.
The resulting code is:
-(void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
self.selectedRow = indexPath.row;
[self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionTop animated:NO];
[self.tableView beginUpdates];
[self.tableView endUpdates];
}
So, automagically there isn't any disappearing row :)
In my UIViewController, I have a table view whose cells show text. The datasource and delegate of the UITableView is my UIViewController. The text to be showed by the cells is stored in an NSMutableArray.
I am able to populate the cells with the text initially, but I also want to implement a functionality, when a user clicks on a specific row the cell gets removed and the table is reloaded.
Here's my code and it's details:
taskList is a NSMutableArray
png images are ones that i need to add in every cell
my table contains only one section
the last row of the table will always show "Create New Task" with a "+" sign as an image
as user adds other task (handled by a separate controller), the taask gets added to the current table.The task will have a "-" sign image.
When user clicks on such a row, it will get deleted from the table
UIViewController's code:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
taskList = [[NSMutableArray alloc] init];
addNewTask = [[AddTaskViewController alloc] init];
[taskList addObject:#"Create New Task"];
[taskList addObject:#"aaaaa"];
[taskList addObject:#"bbbbb"];
[taskList addObject:#"ccccc"];
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
indexNumberInTaskList = [taskList count] - 1;
return [taskList count];
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell;
cell = [tableView dequeueReusableCellWithIdentifier:#"myCell"];
if(cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"myCell"];
}
if(indexNumberInTaskList >= 0)
{
cell.textLabel.text = [taskList objectAtIndex:indexNumberInTaskList];
if(indexPath.row == ([taskList count] - 1))
{
cell.imageView.image = [UIImage imageNamed:#"add.png"];
}
else
{
cell.imageView.image = [UIImage imageNamed:#"remove.png"];
}
indexNumberInTaskList = indexNumberInTaskList - 1;
}
return cell;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
int selectedRow = indexPath.row;
if(selectedRow == ([taskList count]-1))
{
[self presentViewController:addNewTask animated:YES completion:NULL];
}
else
{
[taskList removeObjectAtIndex:indexPath.row];
[self.createDaily reloadData];
}
}
The least amount of code way would be:
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[self.modelArray removeObjectAtIndex:indexPath.row];
[tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
}
These are only required to batch multiple changes together:
[tableView beginUpdates];
[tableView endUpdates];
You can use didSelectRowAtindexPath method of tableview
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[arrayData removeObjectAtIndex:indexPath.row];
[tableView beginUpdates];
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow: indexPath.row inSection:0]] withRowAnimation:UITableViewRowAnimationRight];
[tableView endUpdates];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[YourArr removeObjectAtIndex:indexPath.row];
[YourTbl reloadData];
}
Under your -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath delegate method,
(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath`
NSArray *toBeDeleted = [[NSArray alloc] initWithObjects: indexPath];
// Data deletion
[tableData removeObjectAtIndex:(indexPath.row)];
[tableView beginUpdates];
[tableView deleteRowsAtIndexPaths:toBeDeleted withRowAnimation:UITableViewRowAnimationFade];
[tableView endUpdates];
}
Edit: seems everybody has the same answer!
Add this method
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[arrData removeObjectAtIndex:indexPath.row];
[tableView beginUpdates];
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow: indexPath.row inSection:0]] withRowAnimation:UITableViewRowAnimationRight];
[tableView endUpdates];
}
I had my app working fine on iOS 6. With the upgrade I stopped being able to delete rows from my UITableView.
I've a button in my prototype cell.
Here is the button's function:
- (IBAction)deleteCell:(id)sender {
UIButton *btn = (UIButton*) sender;
UITableViewCell *cell = (UITableViewCell*) btn.superview.superview;
NSIndexPath *indexPath = [_tableView indexPathForCell:cell];
if([names count] > 9) {
int index = indexPath.row;
[names removeObjectAtIndex:index];
[photos removeObjectAtIndex:index];
[_tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationRight];
}
}
The problem is my index variable is always 0.
I tried another solution:
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
int index = indexPath.row;
[names removeObjectAtIndex:index];
[photos removeObjectAtIndex:index];
[_tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationRight];
}
}
This solution doesn't work either. Nothing happens when I swipe right.
Try this sample tutorial,
ViewController.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController<UITableViewDelegate,UITableViewDataSource>
{
NSMutableArray *arryData1;
NSMutableArray *arryData2;
IBOutlet UITableView *tableList;
}
#end
ViewController.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
-(void)viewDidLoad
{
[super viewDidLoad];
arryData1 = [[NSMutableArray alloc] initWithObjects:#"MCA",#"MBA",#"BTech",#"MTech",nil];
arryData2 = [[NSMutableArray alloc] initWithObjects:#"Objective C",#"C++",#"C#",#".net",nil];
tableList.editing=YES;
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [arryData1 count];
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier= #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] ;
}
cell.textLabel.text = [arryData1 objectAtIndex:indexPath.row];
cell.detailTextLabel.text = [arryData2 objectAtIndex:indexPath.row];
return cell;
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
int index = indexPath.row;
[arryData1 removeObjectAtIndex:index];
[arryData2 removeObjectAtIndex:index];
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
withRowAnimation:UITableViewRowAnimationFade];
}
}
- (UITableViewCellEditingStyle)tableView:(UITableView *)aTableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (tableList.editing)
{
return UITableViewCellEditingStyleDelete;
}
return UITableViewCellEditingStyleNone;
}
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
return YES;
}
I quess the problem is you're not reloading data again thus it's staying in cache memory
You can try to reload data with [tableView reloadData]; this method to the below of
[_tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationRight];
this code line in your second solution.
To show delete button on cell swipe you must implement this delegate method.
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
// Return YES if you want the specified item to be editable.
return YES;
}
Try this, i hope this will work for you.
Use the tableview commiteditingstyle method to delete a cell/row of the tableviewcontroller.
Here is the workable code snip:
-(void) tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
[ArrayHoldsCellObj removeObjectAtIndex:indexPath.row];
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
}
Note that the ArrayHoldsCellObj is the Array object you must declare and assign each cell to the area index.
You can set the button tag = cell.index in cellForRowAtIndexPath.
And then
UITableViewCell *cell = (UITableViewCell *)
[tableView cellForRowAtIndexPath:
[NSIndexPath indexPathForRow:btn.tag inSection:0]];
so you can get the index
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
//add code here for when you hit delete
[dataSourceArray removeObjectAtIndex:indexPath.row];
[tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
}
}
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.