I have a UITableView, where there is a UISegmentedControl in the header view. It should work exactly like in the App Store app: As the user scrolls, the title in the header scrolls off the screen but the segmentedControl sticks under the navigationBar.
When the user selects a segment, the section below the header should be reloaded with a nice UITableViewRowAnimation. However, as I call tableView:reloadSections:withRowAnimation:, the header view is animated as well, which I want to prevent, because it looks terrible.
Here's my code for this:
- (void)selectedSegmentIndexChanged:(UISegmentedControl *)sender
{
int index = sender.selectedSegmentIndex;
if (index < self.oldIndex) {
[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationLeft];
} else if (index > self.oldIndex) {
[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationRight];
}
self.oldIndex = index;
}
Anyone has an idea how to reload the section below the header without reloading the header itself?
Maybe you should try with
[self.tableView reloadRowsAtIndexPaths:[self.tableView indexPathsForVisibleRows] withRowAnimation:UITableViewRowAnimationLeft] //or UITableViewRowAnimationRight
However, I'm not sure but I think it can rise some error in the case where you have less rows to reload than previously.
Edit
I think you could deal with [tableView beginUpdates] and [tableView endUpdates] to solve your problem.
For example, you have 2 arrays of data to display. Let name them oldArray and newArray.
A sample of how what you could do :
- (void)selectedSegmentIndexChanged:(UISegmentedControl *)sender
{
[self.tableView setDataSource: newArray];
int nbRowToDelete = [oldArray count];
int nbRowToInsert = [newArray count];
NSMutableArray *indexPathsToInsert = [[NSMutableArray alloc] init];
for (NSInteger i = 0; i < nbRowToInsert; i++) {
[indexPathsToInsert addObject:[NSIndexPath indexPathForRow:i inSection:section]];
}
NSMutableArray *indexPathsToDelete = [[NSMutableArray alloc] init];
for (NSInteger i = 0; i < nbRowToDelete; i++) {
[indexPathsToDelete addObject:[NSIndexPath indexPathForRow:i inSection:section]];
}
[self.tableView beginUpdates];
[self.tableView deleteRowsAtIndexPaths:indexPathsToDelete withRowAnimation:UITableViewRowAnimationLeft];
[self.tableView insertRowsAtIndexPaths:indexPathsToInsert withRowAnimation:UITableViewRowAnimationRight];
[self.tableView endUpdates];
}
If you are using Swift 2.0, feel free to use this extension.
Be warned: passing in the wrong oldCount or newCount will crash you program.
extension UITableView{
func reloadRowsInSection(section: Int, oldCount:Int, newCount: Int){
let maxCount = max(oldCount, newCount)
let minCount = min(oldCount, newCount)
var changed = [NSIndexPath]()
for i in minCount..<maxCount {
let indexPath = NSIndexPath(forRow: i, inSection: section)
changed.append(indexPath)
}
var reload = [NSIndexPath]()
for i in 0..<minCount{
let indexPath = NSIndexPath(forRow: i, inSection: section)
reload.append(indexPath)
}
beginUpdates()
if(newCount > oldCount){
insertRowsAtIndexPaths(changed, withRowAnimation: .Fade)
}else if(oldCount > newCount){
deleteRowsAtIndexPaths(changed, withRowAnimation: .Fade)
}
if(newCount > oldCount || newCount == oldCount){
reloadRowsAtIndexPaths(reload, withRowAnimation: .None)
}
endUpdates()
}
Try this:
BOOL needsReloadHeader = YES;
UIView *oldHeaderView = nil;
-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
UIView *headerToReturn = nil;
if(needsReloadHeader == YES) {
headerToReturn = [[UIView alloc] init];
// ...
// custom your header view in this block
// and save
// ...
oldHeaderView = headerToReturn;
} else {
headerToReturn = oldHeaderView;
}
return headerToReturn;
}
Your just need to change 'needsReloadHeader' to 'NO' in other places.
An objective-c version of Intentss extension
#interface UITableView (Extensions)
- (void)reloadRowsInSection:(NSUInteger)sectionIndex withRowAnimation:(UITableViewRowAnimation)rowAnimation oldCount:(NSUInteger)oldCount newCount:(NSUInteger)newCount;
#end
#implementation UITableView (Extensions)
- (void)reloadRowsInSection:(NSUInteger)sectionIndex withRowAnimation:(UITableViewRowAnimation)rowAnimation oldCount:(NSUInteger)oldCount newCount:(NSUInteger)newCount {
NSUInteger minCount = MIN(oldCount, newCount);
NSMutableArray *insert = [NSMutableArray array];
NSMutableArray *delete = [NSMutableArray array];
NSMutableArray *reload = [NSMutableArray array];
for (NSUInteger row = oldCount; row < newCount; row++) {
[insert addObject:[NSIndexPath indexPathForRow:row inSection:sectionIndex]];
}
for (NSUInteger row = newCount; row < oldCount; row++) {
[delete addObject:[NSIndexPath indexPathForRow:row inSection:sectionIndex]];
}
for (NSUInteger row = 0; row < minCount; row++) {
[reload addObject:[NSIndexPath indexPathForRow:row inSection:sectionIndex]];
}
[self beginUpdates];
[self insertRowsAtIndexPaths:insert withRowAnimation:rowAnimation];
[self deleteRowsAtIndexPaths:delete withRowAnimation:rowAnimation];
[self reloadRowsAtIndexPaths:reload withRowAnimation:rowAnimation];
[self endUpdates];
}
#end
You're reloading the section, so clearly everything in the section will be reloaded (including the header).
Why not instead place the UISegmentedControl inside UITableView's tableHeaderView? This would allow for exactly the behavior you're after.
The simple answer is just don't reload the sections animated, just use UITableViewRowAnimationNone.
Right now you're using UITableViewRowAnimationLeft and UITableViewRowAnimationRight, which slides your section in and out as well.
However, even with UITableViewRowAnimationNone, rows will still be animated if the number of cells before the update differ from the ones after the update.
Also, a nice read on this topic, here.
Cheers.
Here's another way which you could use and still use animations.
Let's say you have a dynamic DataSource, which changes when you select something, and you want to update just the rows of that section, while leaving the section header on top, untouched.
/** I get the desired handler from the handler collection. This handler is just a
simple NSObject subclass subscribed to UITableViewDelegate and UITableViewDataSource
protocols. **/
id handler = [self.tableViewHandlers objectForKey:[NSNumber numberWithInteger:index]];
/** Get the rows which will be deleted */
NSInteger numberOfRows = [self.tableView numberOfRowsInSection:sectionIndex];
NSMutableArray* indexPathArray = [NSMutableArray array];
for (int rowIndex = 0; rowIndex < numberOfRows; rowIndex++){
[indexPathArray addObject:[NSIndexPath indexPathForRow:rowIndex inSection:sectionIndex]];
}
/** Update the handler */
[self.tableView setDataSource:handler];
[self.tableView setDelegate:handler];
/** Get the rows which will be added */
NSInteger newNumberOfRows = [handler tableView:self.tableView numberOfRowsInSection:sectionIndex];
NSMutableArray* newIndexPathArray = [NSMutableArray array];
for (int rowIndex = 0; rowIndex < newNumberOfRows; rowIndex++){
[newIndexPathArray addObject:[NSIndexPath indexPathForRow:rowIndex inSection:sectionIndex]];
}
/** Perform updates */
[self.tableView beginUpdates];
[self.tableView deleteRowsAtIndexPaths:indexPathArray withRowAnimation:UITableViewRowAnimationFade];
[self.tableView insertRowsAtIndexPaths:newIndexPathArray withRowAnimation:UITableViewRowAnimationFade];
[self.tableView endUpdates];
As a note, please stick to the specified order of operations, UITableView demands it.
If you have only one handler (datasource and delegate), it's easy to modify the above code to achieve the same results.
Related
I have a UITableView with expandable sections. When a user goes to another view, I need all the expanded sections to collapse, which I'll need to put in the viewWillDisappear method.
I've found solutions only on how to delete all rows from a table view at once, but is there a way to delete all the rows from a specific section?
EDIT:
I have figured out a solution, but I'm not sure if it's optimal or can lead to inefficiencies in the future. Whenever a cell is expanded, it gets added to an NSMutableIndexSet. So in my viewWillDisappear method, I iterate over the expanded sections like so:
-(void)viewWillDisappear:(BOOL)animated
{
if (expandedSections.count != 0) {
NSLog(#"COLLAPSING CALLED");
[self.tableView beginUpdates];
NSUInteger section = [expandedSections firstIndex];
do
{
NSInteger rows;
NSMutableArray *tmpArray = [NSMutableArray array];
rows = [self tableView:self.tableView numberOfRowsInSection:section];
[expandedSections removeIndex:section];
for (int i=1; i<rows; i++) {
NSIndexPath *tmpIndexPath = [NSIndexPath indexPathForRow:i inSection:section];
[tmpArray addObject:tmpIndexPath];
}
[self.tableView deleteRowsAtIndexPaths:tmpArray withRowAnimation:UITableViewRowAnimationTop];
NSIndexPath *expandableCellIndexPath = [NSIndexPath indexPathForRow:0 inSection:section];
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:expandableCellIndexPath];
cell.accessoryView = [DTCustomColoredAccessory accessoryWithColor:[self.colorHolder objectAtIndex:section] type:DTCustomColoredAccessoryTypeRight];
section = [expandedSections indexGreaterThanIndex:section];
} while (section != NSNotFound);
[self.tableView endUpdates];
}
}
Please let me know if this is a good solution or, if I'm suspecting correctly, if this will lead to slower transitions between views in the future when there are more rows in each expanded section. Any help or advice would be appreciated. Thanks.
If you want to animate changes, you will need to first update your data source (to return 0 for number of rows in the section) then remove section and add section at the same index path in one transaction between [tv beginUpdates] [tv endUpdates]
Otherwise just update the data source and reload the table on your way back to the VC (if you don't want any animations)
I did not read this in detail but surely the for loop should start at zero.
for (int i=0; i<rows; i++) {
NSIndexPath *tmpIndexPath = [NSIndexPath indexPathForRow:i inSection:section];
[tmpArray addObject:tmpIndexPath];
}
otherwise you will only delete all but the first cells in the section.
I am following a tutorial,where I can expand the table view by adding some sub-cells and collapse the table by removing the sub-cells. I am trying to change how the expand operation should execute. When I tap on a row,it expand and shows the sub-cells,and when I tap on other row,the previous expanded row should close. I am not able to do this . I tried the following but I couldnt make the one row expandable at a time,and the other row should close when one expands.
Note: This code works fine,but to collapse the row,we need to tap twice on the same row. I am trying to collapse when other parent is tapped.
Here is the code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
Node *node = [self nodeForIndexPath:indexPath];
// differenet table view cell prototypes for different node levels
UITableViewCell *cell;
if(node.level == 0)
{
cell = [tableView dequeueReusableCellWithIdentifier:#"level1cell" forIndexPath:indexPath];
}
else
{
cell = [tableView dequeueReusableCellWithIdentifier:#"level2cell" forIndexPath:indexPath];
}
// set the nodes title as row text
cell.textLabel.text = node.title;
// attach the nodeId for later lookup when selected
cell.tag = node.nodeId;
// Configure the cell...
return cell;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
Node *node = [self nodeForIndexPath:indexPath];
// NSLog(#"node id is %ld level is %ld and indexpath.row is %d",(long)node.nodeId,(long)node.level,indexPath.row);
node.expanded = !node.expanded;
if (node.level==0) {
NSLog(#"you tapped parent");
//now check other parents are expanded or not
}else{
NSLog(#"you tapped child");
}
//insertion always happen after deletion
// NSLog(#"you touched at %#,index row is %d",indexPath,indexPath.row);
if(node.expanded )
{
// add n rows
NSMutableArray *indexPaths = [NSMutableArray array];
for(NSInteger i=indexPath.row; i< indexPath.row+node.subNodes.count; i++)
{
[indexPaths addObject:[NSIndexPath indexPathForRow:i+1 inSection:0]];
}
[self.tableView beginUpdates];
[self.tableView insertRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationFade];
[self.tableView endUpdates];
}
else
{
//you store the node refe after row is expanded
// delete n rows
NSMutableArray *indexPaths = [NSMutableArray array];
for(NSInteger i=indexPath.row; i< indexPath.row+node.subNodes.count; i++)
{
[indexPaths addObject:[NSIndexPath indexPathForRow:i+1 inSection:0]];
}
[self.tableView beginUpdates];
[self.tableView deleteRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationFade];
[self.tableView endUpdates];
}
}
#pragma mark - Private helper
-(Node*) nodeForIndexPath:(NSIndexPath*)indexPath
{
int idx = 0;
for(Node *node in _nodes)
{
if(idx == indexPath.row)
{
return node;
}
idx++;
if(node.expanded)
{
for (Node *subNode in node.subNodes)
{
if(idx == indexPath.row)
{
return subNode;
}
idx++;
}
}
}
return nil;
}
KMAccordionTableViewController can helps you?
https://github.com/klevison/KMAccordionTableViewController
Hm... If your current code is working, but you need to tap twice to collapse the open/selected row, perhaps it's because didDeselectRowAtIndexPath: is being called during that first tap in place of didSelectRowAtIndexPath: in order to deselect the selected row. I'd recommend configuring your tableview to allow for multiple selection so that didSelectRowAtIndexPath: is called every time, ex:
- (void)viewDidLoad {
[super viewDidLoad];
tableView.allowsMultipleSelection = YES;
}
I can's seem to be able to remove all table rows. What seems to happen is that only the cells that are in view are removed and then the ones that were out of view move up. Also checked and my data source contains only the cels that are in view at the time of deletion. Heres the code
NSMutableArray *left = [[NSMutableArray alloc]init];
NSMutableArray *right = [[NSMutableArray alloc]init];
for(int i=0;i<dataSource.count;i++){
[dataSource removeObjectAtIndex:i];
NSIndexPath *ip = [NSIndexPath indexPathForRow:i inSection:0];
if(i%2==0)
[left addObject:ip];
else
[right addObject:ip];
}
[_view.tableView beginUpdates];
[_view.tableView deleteRowsAtIndexPaths:[NSArray arrayWithArray:left]
withRowAnimation:UITableViewRowAnimationLeft];
[_view.tableView deleteRowsAtIndexPaths:[NSArray arrayWithArray:right]
withRowAnimation:UITableViewRowAnimationRight];
[_view.tableView endUpdates];
What happens now is that only the cells in view are removed and the rest pop in after the removal (also the issue seems to pop up since the dataSource only contains the rows that are in view for some reason). What i want is to remove all the rows. Any ideas?
The problem is in the for loop condition. The dataSource.count gets smaller each iteration. Try this:
for(int i=0;i<dataSource.count;i++){
NSIndexPath *ip = [NSIndexPath indexPathForRow:i inSection:0];
if(i%2==0)
[left addObject:ip];
else
[right addObject:ip];
}
[dataSource removeAllObjects];
try something like this:
[_view.tableView beginUpdates];
UITableViewRowAnimation animation;
for(int i = dataSource.count - 1; i>= 0; i--)
{
[dataSource removeObjectAtIndex: i];
NSIndexPath* ip = [NSIndexPath indexPathForRow: i
inSection: 0];
if(i % 2 == 0)
{
animation = UITableViewRowAnimationLeft;
}
else
{
animation = UITableViewRowAnimationRight;
}
[_view.tableView deleteRowsAtIndexPaths: #[ip]]
withRowAnimation: animation];
}
[_view.tableView endUpdates];
You can do this in easy way...
[dataSource removeAllObjects];
[_view.tableView reloadData];
i think that you can put your dataSource = #[]; and [self.tableview reloadData]; and remove all cell in your tableview
Okay so I've added a picture of what's going on and this may help visualize the issue a little better.
So once I click on the "Shopping & Deals" section image a list of items or cells drop down; however, as you can see there are still some cells that are hidden under the "Shopping & Deals" image. Now here's the code:
- (void) sectionOpened : (NSInteger) section{
SectionInfo *array = [self.sectionInfoArray objectAtIndex:section];
array.open = YES;
//Google PageView tracker
self.trackedViewName = [NSString stringWithFormat:#"Find Things To Do -- %#",array.category.name];
//Mobile Apptracking track event
[[MobileAppTracker sharedManager] trackActionForEventIdOrName:[NSString stringWithFormat:#"Find Things To Do -- %#",array.category.name] eventIsId:NO];
NSInteger count = [array.category.list count];
NSMutableArray *indexPathToInsert = [[NSMutableArray alloc] init];
for (NSInteger i = 0; i<count;i++)
{
[indexPathToInsert addObject:[NSIndexPath indexPathForRow:i inSection:section]];
}
NSMutableArray *indexPathsToDelete = [[NSMutableArray alloc] init];
NSInteger previousOpenIndex = self.openSectionIndex;
if (previousOpenIndex != NSNotFound)
{
SectionInfo *sectionArray = [self.sectionInfoArray objectAtIndex:previousOpenIndex];
sectionArray.open = NO;
NSInteger counts = [sectionArray.category.list count];
[sectionArray.sectionView toggleButtonPressed:FALSE];
for (NSInteger i = 0; i<counts; i++)
{
[indexPathsToDelete addObject:[NSIndexPath indexPathForRow:i inSection:previousOpenIndex]];
}
}
UITableViewRowAnimation insertAnimation;
UITableViewRowAnimation deleteAnimation;
if (previousOpenIndex == NSNotFound || section < previousOpenIndex)
{
insertAnimation = UITableViewRowAnimationTop;
deleteAnimation = UITableViewRowAnimationBottom;
}
else
{
insertAnimation = UITableViewRowAnimationBottom;
deleteAnimation = UITableViewRowAnimationTop;
}
[atableView beginUpdates];
[atableView insertRowsAtIndexPaths:indexPathToInsert withRowAnimation:insertAnimation];
[atableView setContentOffset:CGPointMake(0, self.view.bounds.size.height)];
[atableView deleteRowsAtIndexPaths:indexPathsToDelete withRowAnimation:deleteAnimation];
[atableView endUpdates];
self.openSectionIndex = section;
}
Now if you look at the bottom of the code there's this:
[atableView setContentOffset:CGPointMake(0, self.view.bounds.size.height)];
and this offsets the view according the y bounds. The reason for this was because if you look at the picture, once I clicked on the "Productivity" section the cells would drop down past the view and you couldn't tell if any cells had actually populated, so offsetting the content pushed the view up so that those cells would appear. Now the issue is that once I click on "Shopping & Deals" the cells just kind of hang underneath the section. Does anyone have any ideas on how to tackle this one?
I have a UITableView with several sections.
I would like click on a section to "close/open" its content, in order to show/hide the rows under it. So that, I can keep some sections open (with its rows visible) and others close, with the next section immediately below the previous section header.
How can I implement it? Do I need to subclass the UITableView and add a gesture recognizer and somehow add an animation to the rows? But I'm not sure this is easy...
thanks
Use reloadSections:withRowAnimation to trigger the change;
Provide the updated number of rows in UITableViewDataSource delegate
I can't comment for the question as I don't have enough reputation.
As per my understanding, you want to achieve accordion functionality for your table view. For this, please check this:- effect or animation in UItableVIew and How to implement an accordion view for an iPhone SDK app?
Just subclass sectionHeaderView and define delegate methods like this.
#protocol SectionHeaderViewDelegate <NSObject>
#optional
-(void)sectionHeaderView:(SectionHeaderView*)sectionHeaderView sectionOpened:(NSInteger)section;
-(void)sectionHeaderView:(SectionHeaderView*)sectionHeaderView sectionClosed:(NSInteger)section;
#end
And then in tableViewCOntroller.h
#interface TableViewController : UITableViewController <SectionHeaderViewDelegate>
And in tableViewCOntroller.m
-(void)sectionHeaderView:(SectionHeaderView*)sectionHeaderView sectionOpened:(NSInteger)sectionOpened
{
SectionInfo *sectionInfo = [self.sectionInfoArray objectAtIndex:sectionOpened];
sectionInfo.open = YES;
/*
Create an array containing the index paths of the rows to insert: These correspond to the rows for each quotation in the current section.
*/
NSInteger countOfRowsToInsert = [sectionInfo.play.quotations count];
NSMutableArray *indexPathsToInsert = [[NSMutableArray alloc] init];
for (NSInteger i = 0; i < countOfRowsToInsert; i++) {
[indexPathsToInsert addObject:[NSIndexPath indexPathForRow:i inSection:sectionOpened]];
}
/*
Create an array containing the index paths of the rows to delete: These correspond to the rows for each quotation in the previously-open section, if there was one.
*/
NSMutableArray *indexPathsToDelete = [[NSMutableArray alloc] init];
NSInteger previousOpenSectionIndex = self.openSectionIndex;
if (previousOpenSectionIndex != NSNotFound) {
SectionInfo *previousOpenSection = [self.sectionInfoArray objectAtIndex:previousOpenSectionIndex];
previousOpenSection.open = NO;
[previousOpenSection.headerView toggleOpenWithUserAction:NO];
NSInteger countOfRowsToDelete = [previousOpenSection.play.quotations count];
for (NSInteger i = 0; i < countOfRowsToDelete; i++) {
[indexPathsToDelete addObject:[NSIndexPath indexPathForRow:i inSection:previousOpenSectionIndex]];
}
}
// Style the animation so that there's a smooth flow in either direction.
UITableViewRowAnimation insertAnimation;
UITableViewRowAnimation deleteAnimation;
if (previousOpenSectionIndex == NSNotFound || sectionOpened < previousOpenSectionIndex) {
insertAnimation = UITableViewRowAnimationTop;
deleteAnimation = UITableViewRowAnimationBottom;
}
else {
insertAnimation = UITableViewRowAnimationBottom;
deleteAnimation = UITableViewRowAnimationTop;
}
// Apply the updates.
[self.tableView beginUpdates];
[self.tableView insertRowsAtIndexPaths:indexPathsToInsert withRowAnimation:insertAnimation];
[self.tableView deleteRowsAtIndexPaths:indexPathsToDelete withRowAnimation:deleteAnimation];
[self.tableView endUpdates];
self.openSectionIndex = sectionOpened;
}
-(void)sectionHeaderView:(SectionHeaderView*)sectionHeaderView sectionClosed:(NSInteger)sectionClosed
{
/*
Create an array of the index paths of the rows in the section that was closed, then delete those rows from the table view.
*/
SectionInfo *sectionInfo = [self.sectionInfoArray objectAtIndex:sectionClosed];
sectionInfo.open = NO;
NSInteger countOfRowsToDelete = [self.tableView numberOfRowsInSection:sectionClosed];
if (countOfRowsToDelete > 0)
{
NSMutableArray *indexPathsToDelete = [[NSMutableArray alloc] init];
for (NSInteger i = 0; i < countOfRowsToDelete; i++) {
[indexPathsToDelete addObject:[NSIndexPath indexPathForRow:i inSection:sectionClosed]];
}
[self.tableView deleteRowsAtIndexPaths:indexPathsToDelete withRowAnimation:UITableViewRowAnimationTop];
}
self.openSectionIndex = NSNotFound;
if ([selectedIndexes count]>0)
{
for(NSIndexPath *indexPath in selectedIndexes)
{
if(sectionClosed == indexPath.section)
{
[sectionInfo.headerView changeOnHighlighted:YES];
break;
}
else
{
[sectionInfo.headerView changeOnHighlighted:NO];
}
}
}
else
{
[sectionInfo.headerView changeOnHighlighted:NO];
}
}
And for further details you can refer this sample project from iOS dev lib..
Here is a simple solution by which you can even create a custom expanded/ collapse view.
here are simple step
1) create a custom view add button over it.
///
join all outlet and create on BOOL variable in view class
#property (weak, nonatomic) IBOutlet UIButton *BtnAction;
#property(assign, nonatomic)BOOL isOpen;
// Create a header where tableview is added and you want it.
here is a simple logic to added as much as you need . I have added which are in headertitle array I wanted it to be dynamic .
NSMutableArray * headerTitle = [NSMutableArray arrayWithObjects:#"Your Order", #"Delivery Address", #"Pay By", nil];
for (NSUInteger index = 0; index<headerTitle.count; index++) {
VGOrderHeader* HeaderView = [[[NSBundle mainBundle] loadNibNamed:#"VGOrderHeader" owner:self options:nil] lastObject];
HeaderView.frame = CGRectMake(0, 0, 32, 40);
HeaderView.BtnAction.tag = index;
if (index == 0) {
HeaderView.isOpen = YES;
HeaderView.lblPlus.text = [NSString stringWithFormat:#"open"];
}
[HeaderView.BtnAction addTarget:self action:#selector(selectSectionToOpen:) forControlEvents:UIControlEventTouchUpInside];
[headerArray addObject:HeaderView];
}
/// Here is header click action.
-(void)selectSectionToOpen:(UIButton *)sender{
for (NSUInteger Increment=0; Increment<headerArray.count; Increment++) {
if (sender.tag == Increment) {
DCOrderHeader* HeaderView= headerArray[Increment];
HeaderView.isOpen = !HeaderView.isOpen;
}
}
// little animation
dispatch_async(dispatch_get_main_queue(), ^{
[UIView transitionWithView:self.tableView
duration:0.55f
options:UIViewAnimationOptionTransitionCrossDissolve
animations:^(void) {
[self.tableView reloadData];
} completion:NULL];
});
}
/// Finally Assign view in header method of table view and provide a height
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
return 40;
}
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
return [headerArray objectAtIndex:section];
}
// Final Touch
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return headerArray.count;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
DCOrderHeader* HeaderView = headerArray[section];
if (HeaderView.isOpen == YES) {
return self.someArray.count;
}else{
return 0;
}
}