update UITableView sectionHeaderHeight at time of UIButton click in iOS - ios

Good day! My default tableview sectionHeaderHeight is 56. I want to update it when sectionOpened method gets called.This is the following code:
- (void) sectionOpened : (NSInteger) section
{
sectionHeight = #"YES";
getsection = section;
NSLog(#"Section Clicked: %ld",(long)getsection);
SectionInfo *array = [self.sectionInfoArray objectAtIndex:section];
array.open = YES;
NSInteger count = [array.category.menulist 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.menulist 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;
}
[menulistTable beginUpdates];
if(section==3 || section==4 || section==5) // this section has cells like submenu of a menu
{
menulistTable.sectionHeaderHeight = 20.0;
[menulistTable reloadSections:[NSIndexSet indexSetWithIndex:section] withRowAnimation:UITableViewRowAnimationNone];
//[menulistTable reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationNone];
}
[menulistTable insertRowsAtIndexPaths:indexPathToInsert withRowAnimation:insertAnimation];
[menulistTable deleteRowsAtIndexPaths:indexPathsToDelete withRowAnimation:deleteAnimation];
[menulistTable endUpdates];
self.openSectionIndex = section;
}
But nothing happening. I also used indexSetWithIndex:0. Whats wrong in the code?

Try like this to change Height:
[menulistTable beginUpdates];
menulistTable.sectionHeaderHeight = 20.0;
[menulistTable endUpdates];
Edited:
Take variable to set SectionHeaderHeight. Then place this code:
[menulistTable beginUpdates];
secHeaderHeight = 20.0;
[menulistTable endUpdates];
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
return secHeaderHeight;
}
Hope it will work for you.

Related

UITableView animation issue on insert and delete of cells

I have gone through of various solutions on this but they didn't seem to work. I get consistency exception after insert and delete operations.
For the time being I have used reloadSection method as temporary solution which gives awful animation experience.
How to use insertRowsWithAnimation and deleteRowsWithAnimation which will result in correct animation in the following code :
- (void) imageTapped:(id)sender {
#try {
UIButton *button = sender;
NSInteger tag = button.tag;
GroupNode *group = [[dictGroups objectForKey:#"0"] objectAtIndex:tag];
NSMutableArray *arr = [[CommonModel shared]GetAllGroupNodesByTreeId:group.TreeId];
BOOL isVisited = NO;
GroupNode *nextNode;
for(GroupNode *gp in arr)
{
if(!isVisited)
{
if([gp.Id isEqual:group.Id])
{
isVisited = YES;
}
}
else
{
nextNode = gp;
break;
}
}
if(![group.Indent isEqual:#"0"] && [nextNode.Indent intValue] == [group.Indent intValue] + 1)
{
if ([arrExpandedGroups containsObject:group.Id]) {
[arrExpandedGroups removeObject:group.Id];
NSMutableArray *insertIndexPaths = [[NSMutableArray alloc] init];
NSMutableArray *deleteIndexPaths = [[NSMutableArray alloc] init];
NSMutableArray *arr1 = [dictGroups objectForKey:#"0"];
NSMutableArray *arrDelete = [[NSMutableArray alloc]init];
BOOL isChild = YES;
for(int i = 0; i< arr1.count;i++)
{
GroupNode *gp = [arr1 objectAtIndex:i];
if(![group.Id isEqual:gp.Id])
{
if([arr1 indexOfObject:gp] < [arr1 indexOfObject:group])
{
[arrDelete addObject:gp];
}
else
{
if(([gp.Indent intValue] > [group.Indent intValue]) && !isChild)
{
[arrDelete addObject:gp];
}
else if(([gp.Indent intValue] <= [group.Indent intValue]))
{
[arrDelete addObject:gp];
isChild = NO;
}
else
{
[deleteIndexPaths addObject:[NSIndexPath indexPathForRow:i inSection:0]];
}
}
}
else
{
[arrDelete addObject:gp];
[dictExpand removeObjectForKey:[NSString stringWithFormat:#"%i", (int)button.tag]];
button.tag = [arrDelete indexOfObject:gp];
[dictExpand setObject:#"no" forKey:[NSString stringWithFormat:#"%i", (int)button.tag]];
for(NSString *key in dictExpand.allKeys)
{
if(![key isEqual:[NSString stringWithFormat:#"%i", (int)button.tag]])
{
if([group.Indent intValue] == 1)
[dictExpand setObject:#"no" forKey:key];
}
}
}
}
[tableGroup beginUpdates];
[dictGroups setObject:arrDelete forKey:#"0"];
NSRange range = NSMakeRange(0, 1);
NSIndexSet *sectionToReload = [NSIndexSet indexSetWithIndexesInRange:range];
[tableGroup reloadSections:sectionToReload withRowAnimation:UITableViewRowAnimationNone];
[tableGroup endUpdates];
} else {
if([group.Indent intValue] == 1)
[arrExpandedGroups removeAllObjects];
[arrExpandedGroups addObject:group.Id];
NSMutableArray *arrAdd = [NSMutableArray new];
NSMutableArray *insertIndexPaths = [[NSMutableArray alloc] init];
NSMutableArray *deleteIndexPaths = [[NSMutableArray alloc] init];
NSMutableArray *arr1 = [dictGroups objectForKey:#"0"];
BOOL isVisited = NO;
BOOL isMainVisited = NO;
int icount = 0;
for(GroupNode *gp in arr)
{
BOOL isPresentInArr1 = NO;
for(GroupNode *g in arr1)
{
if([g.Id isEqual:gp.Id] && ![group.Indent isEqual:#"1"])
{
isPresentInArr1 = YES;
break;
}
}
if(!isVisited && (([gp.Indent intValue] == 0 || [gp.Indent intValue] == 1) || isPresentInArr1))
{
[arrAdd addObject:gp];
[insertIndexPaths addObject:[NSIndexPath indexPathForRow:icount inSection:0]];
if([gp.Id isEqual:group.Id])
{
isVisited = YES;
[dictExpand removeObjectForKey:[NSString stringWithFormat:#"%i", (int)button.tag]];
button.tag = [arrAdd indexOfObject:gp];
[dictExpand setObject:#"yes" forKey:[NSString stringWithFormat:#"%i", (int)button.tag]];
for(NSString *key in dictExpand.allKeys)
{
if(![key isEqual:[NSString stringWithFormat:#"%i", (int)button.tag]])
{
if([group.Indent intValue] == 1)
[dictExpand setObject:#"no" forKey:key];
}
}
}
}
else if(isVisited)
{
if([gp.Indent intValue] > [group.Indent intValue] && ([gp.Indent intValue] == [group.Indent intValue] + 1) && !isMainVisited)
{
[arrAdd addObject:gp];
[insertIndexPaths addObject:[NSIndexPath indexPathForRow:icount inSection:0]];
}
else if([group.Indent intValue] > 1 && [gp.Indent intValue] == [group.Indent intValue] && !isMainVisited)
{
[arrAdd addObject:gp];
[insertIndexPaths addObject:[NSIndexPath indexPathForRow:icount inSection:0]];
}
else if([gp.Indent intValue] <= 1 && !isMainVisited)
{
[arrAdd addObject:gp];
[insertIndexPaths addObject:[NSIndexPath indexPathForRow:icount inSection:0]];
isMainVisited = YES;
}
else if([gp.Indent intValue] <= 1 && isMainVisited)
{
[arrAdd addObject:gp];
[insertIndexPaths addObject:[NSIndexPath indexPathForRow:icount inSection:0]];
}
else
{
for(GroupNode *gn in arr1)
{
if([gn.Id isEqual:gp.Id])
[deleteIndexPaths addObject:[NSIndexPath indexPathForRow:icount inSection:0]];
}
}
}
icount ++;
}
[dictGroups setObject:arrAdd forKey:#"0"];
[tableGroup beginUpdates];
NSRange range = NSMakeRange(0, 1);
NSIndexSet *sectionToReload = [NSIndexSet indexSetWithIndexesInRange:range];
[tableGroup reloadSections:sectionToReload withRowAnimation:UITableViewRowAnimationNone];
[tableGroup endUpdates];
}
}
}
#catch (NSException *exception) {
}
}
I am aware this is a complex logic but this is how it will work.
arr - All database records array
arr1 - All displayed records
numberOfRowsInSection :
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
int count = (int)[[dictGroups objectForKey:#"0"] count];
return count;
}
This number is always same as the number of records in array in imageTapped function.
Insert row in table view as well when you are adding it in array. you are at once reloading the whole section... may be that might be a problem!(m not sure!!!)
Add this when you are updating index path while adding row:
[tableView insertRowsAtIndexPaths:[NSMutableArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
and this when deleting the index:
[tableView deleteRowsAtIndexPaths:[NSMutableArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
may be this can help and if not then try changing following line from your code:
[tableGroup reloadSections:sectionToReload withRowAnimation:UITableViewRowAnimationNone];
to:
[tableGroup reloadSections:sectionToReload withRowAnimation:UITableViewRowAnimationFade];
At first delete that object from tableview array, then use
[table deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationBottom];
[table reloadData];

Remove Rows From UITableView from Previous Selected Section

Currently I have a UITableView which is expands and collapses with the current code.
- (BOOL)tableView:(UITableView *)tableView canCollapseSection:(NSInteger)section{
if (section>=0) return YES;
return NO;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
NSInteger numberofRows = 0;
numberofRows = nameArray.count;
if (numberofRows != 0){
self.mainTableView.hidden = false;
}
return numberofRows;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
if ([self tableView:tableView canCollapseSection:indexPath.section])
{
if (!indexPath.row)
{
// only first row toggles exapand/collapse
[tableView deselectRowAtIndexPath:indexPath animated:YES];
NSInteger section = indexPath.section;
BOOL currentlyExpanded = [expandedSections containsIndex:section];
NSInteger rows;
NSMutableArray *tmpArray = [NSMutableArray array];
if (currentlyExpanded)
{
rows = [self tableView:tableView numberOfRowsInSection:section];
[expandedSections removeIndex:section];
}
else
{
[expandedSections addIndex:section];
rows = [self tableView:tableView numberOfRowsInSection:section];
}
for (int i=1; i<rows; i++)
{
NSIndexPath *tmpIndexPath = [NSIndexPath indexPathForRow:i
inSection:section];
[tmpArray addObject:tmpIndexPath];
}
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if (currentlyExpanded)
{
[tableView deleteRowsAtIndexPaths:tmpArray
withRowAnimation:UITableViewRowAnimationTop];
cell.accessoryView = [ALCustomColoredAccessory accessoryWithColor:[UIColor grayColor] type:ALCustomColoredAccessoryTypeDown];
}
else
{
[tableView insertRowsAtIndexPaths:tmpArray
withRowAnimation:UITableViewRowAnimationTop];
cell.accessoryView = [ALCustomColoredAccessory accessoryWithColor:[UIColor grayColor] type:ALCustomColoredAccessoryTypeUp];
}
}
else {
NSLog(#"Selected Section is %ld and subrow is %ld ",(long)indexPath.section ,(long)indexPath.row);
}
}
}
This works really well and upon selection of a UITableViews section the rows are expanded and populated with the correct data and when the same section is selected the rows are removed and appear collapsed.
However what i want to do is somehow automatically collapse the previous selected section and remove the rows within that previous section when the user selects a new indexpath.section.
I have tried storing the selected section index path to an array removing rows based on this value but I think I'm going about it the wrong way as I get assertion failures.
So my question is as follows :-
How can i automatically collapse (remove rows) from a uitableviews section upon selection of another section
Thanks for your help in advance
Thomas
i have faced this issue when i was writting code for my app and i founded this post that had no any single comment or answer...
You can use this code that i was written for me to colapse previous expanded rows of section when i clicked on other section and expand rows of that section, this code working for me try it...
`
- (BOOL)tableView:(UITableView *)tableView canCollapseSection:(NSInteger)section
{
if (section>=0) return YES;
return NO;
}
static NSInteger Value=0;
static NSInteger Value2=0;
static CFIndex indexPre=0;
static NSMutableArray *preArray;
static NSIndexPath *path;
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([self tableView:tableView canCollapseSection:indexPath.section])
{
if (!indexPath.row)
{
TableViewCell *cell = (TableViewCell *)[tableView cellForRowAtIndexPath:indexPath];
cell.hideButton.hidden=NO;
[tableView deselectRowAtIndexPath:indexPath animated:YES];
NSUInteger index=[expandedSections firstIndex];
if ([expandedSections indexGreaterThanIndex:index])
{
NSLog(#"%lu hhhwww", index);
}
NSInteger section = indexPath.section;
static NSInteger rows;
static NSInteger PreRows;
NSLog(#"%lu MY INDEXES1",(unsigned long)[expandedSections count]);
NSMutableArray *tmpArray = [NSMutableArray array];
preArray = [NSMutableArray array];
BOOL currentlyExpanded = [expandedSections containsIndex:section];
if (currentlyExpanded)
{
rows = [self tableView:tableView numberOfRowsInSection:section];
[expandedSections removeIndex:section];
Value=0;
Value2=0;
cell.hideButton.hidden=YES;
}
else
{
if (Value==0)
{
[expandedSections addIndex:section];
rows = [self tableView:tableView numberOfRowsInSection:section];
PreRows = [self tableView:tableView numberOfRowsInSection:section];
indexPre=indexPath.section;
Value=1;
}
else if (Value==1)
{
Value2=1;
NSLog(#"indexPre == %ld %# my indexxxxx", indexPre, expandedSections);
[expandedSections removeIndex:indexPre];
NSLog(#"indexPre == %ld %# my indexxxxx", indexPre, expandedSections);
[self.tableView reloadData];
[expandedSections addIndex:section];
NSLog(#"indexPre == %ld %# my indexxxxx", indexPre, expandedSections);
rows=[self tableView:tableView numberOfRowsInSection:section];
}
}
NSLog(#"%# MY INDEXES",expandedSections);
if (Value2==1)
{
for (int i=1; i<PreRows; i++)
{
NSIndexPath *tmpIndexPath = [NSIndexPath indexPathForRow:i
inSection:indexPre];
[preArray addObject:tmpIndexPath];
}
NSLog(#"my arrray %#", preArray);
for (int i=1; i<rows; i++)
{
NSIndexPath *tmpIndexPath = [NSIndexPath indexPathForRow:i
inSection:section];
[tmpArray addObject:tmpIndexPath];
}
NSLog(#"my arrray tmparray%#", preArray);
}
else
{
for (int i=1; i<rows; i++)
{
NSIndexPath *tmpIndexPath = [NSIndexPath indexPathForRow:i
inSection:section];
[tmpArray addObject:tmpIndexPath];
}
}
if (currentlyExpanded )
{
[tableView deleteRowsAtIndexPaths:tmpArray
withRowAnimation:NO];
cell.accessoryView = [DTCustomColoredAccessory accessoryWithColor:[UIColor grayColor] type:DTCustomColoredAccessoryTypeDown];
}
else if(Value==1)
{
if (Value2==1)
{
[tableView beginUpdates];
[tableView insertRowsAtIndexPaths:tmpArray
withRowAnimation:NO];
cell.accessoryView = [DTCustomColoredAccessory accessoryWithColor:[UIColor grayColor] type:DTCustomColoredAccessoryTypeUp];
[tableView endUpdates];
[tableView beginUpdates];
[tableView endUpdates];
indexPre=indexPath.section;
}
else
{
[tableView insertRowsAtIndexPaths:tmpArray
withRowAnimation:UITableViewRowAnimationTop];
cell.accessoryView = [DTCustomColoredAccessory accessoryWithColor:[UIColor grayColor] type:DTCustomColoredAccessoryTypeUp];
}
}
}
}
}
`

Unable to figure out the value change of the integer in the code

I have this code and I am trying to understand it. This has an int value 'currentExpandIndex' ,I couldnt figure out why it is changing because I dont find proper initiation of it. The int is first given the value -1,but later in code the int value changes according to the indexpath. I coldnt find the relation between the int and the indexpath declared in the code.Kindly tell me,why
the code is:
#interface AccordionTableViewController : UITableViewController {
NSArray *topItems;
NSMutableArray *subItems; // array of arrays
int currentExpandedIndex;
}
#end
//.m file
- (id)init {
self = [super init];
if (self) {
topItems = [[NSArray alloc] initWithArray:[self topLevelItems]];
subItems = [NSMutableArray new];
currentExpandedIndex = -1;
NSLog(#"currenyt index -init is %d",currentExpandedIndex);
for (int i = 0; i < [topItems count]; i++) {
[subItems addObject:[self subItems]];
}
}
return self;
}
#pragma mark - Data generators
- (NSArray *)topLevelItems {
NSMutableArray *items = [NSMutableArray array];
for (int i = 0; i < NUM_TOP_ITEMS; i++) {
[items addObject:[NSString stringWithFormat:#"Item %d", i + 1]];
}
return items;
}
- (NSArray *)subItems {
NSMutableArray *items = [NSMutableArray array];
int numItems = arc4random() % NUM_SUBITEMS + 2;
for (int i = 0; i < numItems; i++) {
[items addObject:[NSString stringWithFormat:#"SubItem %d", i + 1]];
}
return items;
}
#pragma mark - View management
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(#"currenyt index -view did load is %d",currentExpandedIndex);
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSLog(#"currenyt index -no of rows in section is %d",currentExpandedIndex);
return [topItems count] + ((currentExpandedIndex > -1) ? [[subItems objectAtIndex:currentExpandedIndex] count] : 0);
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *ParentCellIdentifier = #"ParentCell";
static NSString *ChildCellIdentifier = #"ChildCell";
NSLog(#"currenyt index-cell for row at index is %d",currentExpandedIndex);
BOOL isChild =
currentExpandedIndex > -1
&& indexPath.row > currentExpandedIndex
&& indexPath.row <= currentExpandedIndex + [[subItems objectAtIndex:currentExpandedIndex] count];
UITableViewCell *cell;
if (isChild) {
cell = [tableView dequeueReusableCellWithIdentifier:ChildCellIdentifier];
}
else {
cell = [tableView dequeueReusableCellWithIdentifier:ParentCellIdentifier];
}
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ParentCellIdentifier] autorelease];
}
if (isChild) {
cell.detailTextLabel.text = [[subItems objectAtIndex:currentExpandedIndex] objectAtIndex:indexPath.row - currentExpandedIndex - 1];
}
else {
int topIndex = (currentExpandedIndex > -1 && indexPath.row > currentExpandedIndex)
? indexPath.row - [[subItems objectAtIndex:currentExpandedIndex] count]
: indexPath.row;
cell.textLabel.text = [topItems objectAtIndex:topIndex];
cell.detailTextLabel.text = #"";
}
return cell;
}
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
BOOL isChild =
currentExpandedIndex > -1
&& indexPath.row > currentExpandedIndex
&& indexPath.row <= currentExpandedIndex + [[subItems objectAtIndex:currentExpandedIndex] count];
if (isChild) {
NSLog(#"A child was tapped, do what you will with it");
NSLog(#"currenyt index -did select is %d",currentExpandedIndex);
return;
}
NSLog(#"currenyt index -did select out is %d",currentExpandedIndex);
[self.tableView beginUpdates];
if (currentExpandedIndex == indexPath.row) {
[self collapseSubItemsAtIndex:currentExpandedIndex];
currentExpandedIndex = -1;
}
else {
BOOL shouldCollapse = currentExpandedIndex > -1;
if (shouldCollapse) {
[self collapseSubItemsAtIndex:currentExpandedIndex];
}
currentExpandedIndex = (shouldCollapse && indexPath.row > currentExpandedIndex) ? indexPath.row - [[subItems objectAtIndex:currentExpandedIndex] count] : indexPath.row;
[self expandItemAtIndex:currentExpandedIndex];
}
[self.tableView endUpdates];
}
- (void)expandItemAtIndex:(int)index {
NSMutableArray *indexPaths = [NSMutableArray new];
NSArray *currentSubItems = [subItems objectAtIndex:index];
int insertPos = index + 1;
for (int i = 0; i < [currentSubItems count]; i++) {
[indexPaths addObject:[NSIndexPath indexPathForRow:insertPos++ inSection:0]];
}
[self.tableView insertRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationFade];
//[self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:index inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:YES];
[indexPaths release];
}
- (void)collapseSubItemsAtIndex:(int)index {
NSMutableArray *indexPaths = [NSMutableArray new];
for (int i = index + 1; i <= index + [[subItems objectAtIndex:index] count]; i++) {
[indexPaths addObject:[NSIndexPath indexPathForRow:i inSection:0]];
}
[self.tableView deleteRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationFade];
[indexPaths release];
}
In didSelectRowAtIndexPath: you have this line:
currentExpandedIndex =
(shouldCollapse && indexPath.row > currentExpandedIndex) ?
indexPath.row - [[subItems objectAtIndex:currentExpandedIndex] count] :
indexPath.row;
This line assign indexPath.row or indexPath.row - [[subItems objectAtIndex:currentExpandedIndex] count] to currentExpandedIndex.
currentExpandedIndex = (shouldCollapse && indexPath.row > currentExpandedIndex) ? indexPath.row - [[subItems objectAtIndex:currentExpandedIndex] count] : indexPath.row;
On each didSelectRow it will change.
First, set a breakpoint in -init. Depending on how you create this controller, it might not be called, in which case it will be 0. Try -initWithCoder: instead if this is the case. Otherwise, I only see this set in one place: -tableView:didSelectRowAtIndexPath:, where it can be set to the row or indexPath.row - [[subItems objectAtIndex:currentExpandedIndex] count]. Depending on what else you are doing with the table, this might be a good job for sections or expandable individual rows to simplify.

Expanding and collapsing tableView sections iOS?

I am able to expand and collapse the tableView sections successfully however I am not able to do it for individual sections so far.So all the sections collapse or expand at the same time, which is because I call [tableView reloadData] .So How can I expand or collapse a particular section?
Here is how I am doing it currently.
-(UIView*)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
headerLabel = [[UILabel alloc]init];
headerLabel.tag = section;
headerLabel.userInteractionEnabled = YES;
headerLabel.backgroundColor = [[UIColor grayColor]colorWithAlphaComponent:0.2];
headerLabel.text = [menuCategoryArray objectAtIndex:section];
headerLabel.frame = CGRectMake(5, 0, tableView.tableHeaderView.frame.size.width, tableView.tableHeaderView.frame.size.height);
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc]initWithTarget:self action:#selector(headerClicked:)];
tapGesture.cancelsTouchesInView = NO;
[headerLabel addGestureRecognizer:tapGesture];
return headerLabel;
}
-(void)headerClicked:(UIGestureRecognizer*)sender
{
if (!isShowingList) {
isShowingList=YES;
[self.menuTableView reloadData];
UILabel *lbl = (UILabel*)sender.view;
NSLog(#"header no : %d", lbl.tag);
}else{
isShowingList=NO;
[self.menuTableView reloadData];
UILabel *lbl = (UILabel*)sender.view;
NSLog(#"header no : %d", lbl.tag);
}
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
if (isShowingList) {
return [[[[jsonArray valueForKey:#"menus"] valueForKey:#"menuName"] objectAtIndex:section] count];
}else{
return 0;
}
return 0;
}
First take isShowingList as
#property (nonatomic, strong) NSMutableArray *isShowingList;
And for identifying previously opened section you need another property
#property (nonatomic, assign) NSInteger openSectionIndex;
when you have the data initialized, isShowingList in you case, initialize isShowingList array before reloading table
self.isShowingList = [NSMutableArray array];
if (jsonArray && [jsonArray valueForKey:#"menus"] && [[jsonArray valueForKey:#"menus"] valueForKey:#"menuName"]) {
for (int i = 0; i < [[[jsonArray valueForKey:#"menus"] valueForKey:#"menuName"] count]; i++) {
[self.isShowingList addObject:[NSNumber numberWithBool:NO]];
}
}
and initialize openSectionIndex in viewDidLoad() like this
self.openSectionIndex = NSNotFound;
and your code should be changed like this
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if ([[self.isShowingList objectAtIndex:section] boolValue]) {
return [[[[jsonArray valueForKey:#"menus"] valueForKey:#"menuName"] objectAtIndex:section] count];
} else {
return 0;
}
return 0;
}
-(void)headerClicked:(UIGestureRecognizer*)sender {
UILabel *lbl = (UILabel*)sender.view;
NSLog(#"header no : %d", lbl.tag);
if ([[self.isShowingList objectAtIndex:lbl.tag] boolValue]) {
[self closeSection:lbl.tag];
} else {
[self openSection:lbl.tag];
}
}
//methods for expanding and collapsing sections
- (void)openSection:(NSInteger)section {
[self.isShowingList replaceObjectAtIndex:section withObject:[NSNumber numberWithBool:YES]];
NSInteger countOfRowsToInsert = [[[[jsonArray valueForKey:#"menus"] valueForKey:#"menuName"] objectAtIndex:section] count];
NSMutableArray *indexPathsToInsert = [[NSMutableArray alloc] init];
for (NSInteger i = 0; i < countOfRowsToInsert; i++) {
[indexPathsToInsert addObject:[NSIndexPath indexPathForRow:i inSection:section]];
}
NSMutableArray *indexPathsToDelete = [[NSMutableArray alloc] init];
NSInteger previousOpenSectionIndex = self.openSectionIndex;
if (previousOpenSectionIndex != NSNotFound) {
dispatch_async(dispatch_get_main_queue(), ^{
[self.menuTableView reloadSections:[NSIndexSet indexSetWithIndex:previousOpenSectionIndex] withRowAnimation:UITableViewRowAnimationNone];
});
[self.isShowingList replaceObjectAtIndex:previousOpenSectionIndex withObject:[NSNumber numberWithBool:NO]];
NSInteger countOfRowsToDelete = [[[[jsonArray valueForKey:#"menus"] valueForKey:#"menuName"] objectAtIndex:previousOpenSectionIndex] count];
for (NSInteger i = 0; i < countOfRowsToDelete; i++) {
[indexPathsToDelete addObject:[NSIndexPath indexPathForRow:i inSection:previousOpenSectionIndex]];
}
}
// Apply the updates.
[self.menuTableView beginUpdates];
[self.menuTableView insertRowsAtIndexPaths:indexPathsToInsert withRowAnimation:UITableViewRowAnimationAutomatic];
[self.menuTableView deleteRowsAtIndexPaths:indexPathsToDelete withRowAnimation:UITableViewRowAnimationAutomatic];
[self.menuTableView endUpdates];
self.openSectionIndex = section;
}
- (void)closeSection:(NSInteger)section {
[self.isShowingList replaceObjectAtIndex:section withObject:[NSNumber numberWithBool:NO]];
NSInteger countOfRowsToDelete = [self.menuTableView numberOfRowsInSection:section];
if (countOfRowsToDelete > 0) {
NSMutableArray *indexPathsToDelete = [[NSMutableArray alloc] init];
for (NSInteger i = 0; i < countOfRowsToInsert; i++) {
[indexPathsToDelete addObject:[NSIndexPath indexPathForRow:i inSection:section]];
}
[self.menuTableView deleteRowsAtIndexPaths:indexPathsToDelete withRowAnimation:UITableViewRowAnimationTop];
}
self.openSectionIndex = NSNotFound;
}
You really would be better off looking at using a 'tableView update block'. Please take a look at this viewController for an answer I posted very recently. The updateBlock allows you to manipulate some variable or other which affects the dataSource, and instruct the table to add/remove rows/sections in order to reflect that change. Note that when you call the endUpdates method the table must not conflict with the model or you'll get an exception.
#import "ViewController.h"
//dont worry, the header is empty except for import <UIKit/UIKit.h>, this is a subclass on UIViewController
#interface ViewController ()<UITableViewDataSource, UITableViewDelegate>
#property (weak, nonatomic) UITableView *tableView;
#end
#implementation ViewController
{
//ivars
BOOL sectionIsOpen[4]; //we will use this BOOL array to keep track of the open/closed state for each section. Obviously I have the number of sections fixed at 4 here, but you could make a more dynamic array with malloc() if neccesary..
}
- (void)viewDidLoad {
[super viewDidLoad];
UITableView *tv = [[UITableView alloc]initWithFrame:self.view.bounds style:UITableViewStyleGrouped];
tv.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
tv.dataSource = self;
tv.delegate = self;
[self.view addSubview:tv];
self.tableView = tv;
// Do any additional setup after loading the view, typically from a nib.
}
#pragma mark - UITableViewDataSource
-(NSInteger )numberOfSectionsInTableView:(UITableView *)tableView{
return 4;
}
-(NSInteger )tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return ((sectionIsOpen[section]) ? [self numberOfRowsInSection:section] : 0);
}
-(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{
//put your switch() here...
return [NSString stringWithFormat:#"I am section %i", (int)section ];
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *cellId = #"cellID";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellId];
if (!cell) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellId];
}
//etc etc decorate your cell...
cell.textLabel.text = [NSString stringWithFormat:#"cell %i / %i", (int)indexPath.section, (int)indexPath.row ];
return cell;
}
#pragma mark - UITableViewDelegate
-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section{
const CGRect fr = CGRectMake(0, 0, 320.0, 40.0 );
UIButton *btn = [[UIButton alloc]initWithFrame:fr];
[btn setTitle:[self tableView:tableView titleForHeaderInSection:section] forState:UIControlStateNormal ];
[btn setTag:section];
[btn addTarget:self action:#selector(sectionOpenToggle:) forControlEvents:UIControlEventTouchUpInside];
// add an image, colour etc if you like
return btn;
}
#pragma mark - tableViewHelpers
//the number of rows in sectionX when it is open...
-(NSInteger )numberOfRowsInSection:(NSInteger )section{
//get your count from your model
return section + 1;
}
//opening/closing a section
-(void )setSection:(NSInteger )section toOpen:(BOOL )open{
if (open != sectionIsOpen[section]) {
//build an array of indexPath objects
NSMutableArray *indxPths = [NSMutableArray array];
for (NSInteger row = 0; row < [self numberOfRowsInSection:section]; row ++) {
[indxPths addObject: [NSIndexPath indexPathForRow:row inSection:section ]
];
}
[self.tableView beginUpdates];
if (open) {
[self.tableView insertRowsAtIndexPaths:indxPths withRowAnimation:UITableViewRowAnimationFade];
//nb there is a large ENUM of tableViewRowAnimation types to experiment with..
}else{
[self.tableView deleteRowsAtIndexPaths:indxPths withRowAnimation:UITableViewRowAnimationFade];
}
sectionIsOpen[section] = open;
[self.tableView endUpdates];
}
}
-(void )sectionOpenToggle:(id )sender{
[self setSection:[sender tag] toOpen: !sectionIsOpen[[sender tag]] ];
}
// open/close all sections.
-(void )setAllSectionsOpen:(BOOL )open{
for (NSInteger section = 0; section < [self numberOfSectionsInTableView:self.tableView]; section ++) {
[self setSection:section toOpen:open];
}
}
//these two for your convenience, hook up to navbar items etc..
-(IBAction)openAllSections:(id)sender{
[self setAllSectionsOpen:YES];
}
-(IBAction)closeAllSections:(id)sender{
[self setAllSectionsOpen:NO];
}
#end

UITableView Expanding Section generated errors

I have a snippet of code of expanding the rows of cells of section. The error occurs at the xtable updates [UIViewAnimation initWithView:indexPath:endRect:endAlpha:startFraction:endFraction:curve:animateFromCurrentPosition:shouldDeleteAfterAnimation:editing:]
Snippet of code
-(void)sectionHeaderView:(SectionHeaderView*)sectionHeaderView sectionOpened:(NSInteger)sectionOpened {
SectionInfo *sectionInfo = [self.sectionInfoArray objectAtIndex:sectionOpened];
sectionInfo.open = YES;
NSInteger countOfRowsToInsert = 5;
NSMutableArray *indexPathsToInsert = [[NSMutableArray alloc] init];
for (NSInteger i = 0; i < countOfRowsToInsert; i++) {
[indexPathsToInsert addObject:[NSIndexPath indexPathForRow:i inSection:sectionOpened]];
}
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 = 5;
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.
[xtable beginUpdates];
[xtable insertRowsAtIndexPaths:indexPathsToInsert withRowAnimation:insertAnimation];
[xtable deleteRowsAtIndexPaths:indexPathsToDelete withRowAnimation:deleteAnimation];
[xtable endUpdates];
self.openSectionIndex = sectionOpened;
}
what could possible be wrong? any ideas?
in my case helped
-(CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
return 0;
}

Resources