numberOfRowsInSection method with expandable and collapsable sections - ios

I am trying to implement expandable and collapsable sections in my tableView. I am following a tutorial to do it, but I would need your help.
expandedSections is a NSMutableIndexSet and canCollapseSection is a BOOL method declared as follows:
-(BOOL)tableView:(UITableView *)tableView canCollapseSection:(NSInteger)section {
if (section >0) return YES;
return NO;
}
This is the numberOfRowsInSection original method:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if ([self tableView:tableView canCollapseSection:section])
{
if ([expandedSections containsIndex:section])
{
return 5; // return rows when expanded
}
return 1; // only top row showing
}
// Return the number of rows in the section.
return 1;
}
And this is my updated code for the same method. I have also implemented a search bar and NSFetchedResultsController to populate the section headers and rows.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (tableView == self.searchDisplayController.searchResultsTableView)
{
return [self.searchResults count];
}
else {
if ([self tableView:tableView canCollapseSection:section])
{
if ([expandedSections containsIndex:section])
{
id<NSFetchedResultsSectionInfo> sectionInfo = [[self.fetchedResultsController sections]objectAtIndex:section];
return [sectionInfo numberOfObjects];
}
return 1;}
}
id<NSFetchedResultsSectionInfo> sectionInfo = [[self.fetchedResultsController sections]objectAtIndex:section];
return [sectionInfo numberOfObjects];
}
The app is not crashing, and the sections are shown, but it is not working as expected. May be you could check my code and tell me what is wrong there.
This is a screenshot from the tableView:

(From my comments:)
The reason that the first section appears to different from the other sections is
that your canCollapseSection method explicitly returns NO for section #0.
There could be another problem in combination with a fetched results controller:
If numberOfRowsInSection returns 1 for a collapsed section (instead of the actual number of rows in that section) then you would also have to modify the FRC delegate methods (so that they do not call insertRows... or deleteRows... for currently "invisible" rows).

Related

indexpath.row showing index 0 every time

So the problem is , in my cellForRowAtIndexPath method everytime indexpath.row is "0" only. And to confirm I have printed the counter with "count". But everytime it is showing 0 and my whole table is allocated with same values. Don't know what's wrong. Please someone help .
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [arr_Max count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 1;
}
-(CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
return 10;
}
-(UITableViewCell *) tableView: (UITableView *) tableView cellForRowAtIndexPath:(NSIndexPath *) indexPath
{
static NSString *simpleTableIdentifier = #"SimpleTableViewCell";
count=(int)indexPath.row;
NSLog(#"%d",count);
SimpleTableViewCell *cell = (SimpleTableViewCell *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"SimpleTableViewCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
cell.label.text=[NSString stringWithFormat:#"%#",[arr_Max objectAtIndex:count] ];
return cell;
}
Your code is error, the correct code is as follows:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection: (NSInteger)section
{
return [arr_Max count];
}
Most likely your tableView delegate method numberOfRowsInSection is returning a bad number of rows.
Ensure that this required delegate method,
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
is returning a valid number - usually the number of elements in your datasource.
You have update your code with following and other part will remain unchanged:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [arr_Max count];
}
It seems you have number or rows = 1 (from numberOfRowsInSection).
So eachtime, when your tableview delegate fires method, it returns 1 rows only.
could you please explain more about ur problem.
For my understanding, you should go on like this code.
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:
(NSInteger)section
{
return [arr_Max count];
}
Then probably you will get the count value based upon your array contents.
please comment if it is ok or any query regarding this.

Hiding UITableView sections with delegate methods not drawing headers correctly afterwards

I have two sections in my UITableView populated by predicate filtering of a single array as their datasource. When the predicate filtered arrays have items in them, the headers are drawn (colored) correctly and are at the correct positions. The colors are set in willDisplayHeaderView.
Note, this is NOT a UITableViewController, but a UITableView that is part of a more complex view.*
New items can be added to the table with an add (+) button.
When I delete items from a section until it has 0 items, the header disappears correctly.
When I add a new item to one of these empty (and now invisible) sections, the header is drawn and named correctly, but it's not colored correctly and appears slightly overlapping the section above it (or in the case of the first/0th section, it appears under the table top so you can't see half the text).
It's almost like willDisplayHeaderView isn't getting called when a section not previously there is now added because it's datasource now has data.
Here are my methods:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return kSectionCount;
}
and
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// Return the number of rows in the section.
switch (section) {
case kIncompleteActivitiesSection:
return [[_activitiesArray filteredArrayUsingPredicate:_predIncomplete] count];
case kCompleteActivitiesSection:
return [[_activitiesArray filteredArrayUsingPredicate:_predComplete] count];
default:
return 0;
}
}
and
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
// return the section names
switch (section) {
case kIncompleteActivitiesSection:
if ([[_activitiesArray filteredArrayUsingPredicate:_predIncomplete] count] > 0) {
return #"Upcoming Activities";
} else {
return nil;
}
case kCompleteActivitiesSection:
if ([[_activitiesArray filteredArrayUsingPredicate:_predComplete] count] > 0) {
return #"Completed Activities";
} else {
return nil;
}
default:
return 0;
}
}
and
- (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section {
// set header text Color
UITableViewHeaderFooterView *header = (UITableViewHeaderFooterView *)view;
[header.textLabel setTextColor:[UIColor whiteColor]];
// set header background color
header.backgroundView = [UIView new];
header.backgroundView.backgroundColor = _colorSchemeColor;
header.backgroundView.alpha = 1.0;
}
When you change your _activitiesArray you have to reload the section(s) that are affected. The section headers are not updated automatically, in my experience.
[self.tableView beginUpdates];
//Update your data model here
[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:section] withRowAnimation:UITableViewRowAnimationFade];
[self.tableView endUpdates];
You can substitute whichever row animation style you prefer.

Combining NSFetchedResultsController with UITableView "insertion control"

I'm trying to get a UITableView to work with Core Data using an NSFetchedResultsController, while also having an insertion control (UITableViewCellStyleInsert) as the last row during editing.
Since the insertion control is just another tableviewcell, just with a different editing style, I have changed the appropriate UITableViewDatasource delegate methods, like:
-(UITableViewCellEditingStyle)tableView:(UITableView *)tableView
editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([self isInsertionControl:indexPath]) {
return UITableViewCellEditingStyleInsert;
} else {
return UITableViewCellEditingStyleDelete;
}
}
The reported number of rows should also be updated accordingly, when editing (assuming there's only one section for now):
(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
id<NSFetchedResultsSectionInfo> sectionInfo = self.fetchedResultsController.sections[section];
NSUInteger numberOfObjects = sectionInfo.numberOfObjects;
// FIXME, things will go out of hand with more than one section.
if (self.tableView.editing) {
return numberOfObjects + 1;
} else {
return numberOfObjects;
}
}
And if requested, return the appropriate cell for the insertion row:
-(UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *tableViewCell = nil;
if ([self isInsertionControl:indexPath]) {
static NSString *InsertIdentifier = #"InsertCell";
tableViewCell = [tableView dequeueReusableCellWithIdentifier:InsertIdentifier
forIndexPath:indexPath];
} else {
tableViewCell = [tableView dequeueReusableCellWithIdentifier:self.cellIdentifier
forIndexPath:indexPath];
[self configureCell:tableViewCell atIndexPath:indexPath];
}
return tableViewCell;
}
This doesn't work, can anybody help me find out why?
QUICK EDIT
To be clear, I have 2 prototype cells in my storyboard, one for the regular content and one for representing the insertion row, both with the appropriate reuse identifier.

iOS: Return 2 count values in numberOfRowsInSection

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
int count = [entries count];
if (count == 0) {
return kCustomRowCount;
}
return count;
int rowCount;
if (self.isFiltered) {
rowCount = filteredTableData.count;
}
else {
rowCount = allTableData.count;
}
return rowCount;
}
My problem: The first function return count; is needed to fill the parsed data into the tableView. The second one return rowCount; is needed to count the filtered entries for the search. But when I use both, my App dies. When I delete the first part, the search seems to work incorrectly..
Sascha
It sounds like you need to be making use of the UISearchDisplayController. This controller essentially supports an unfiltered and a filtered (searched) list.
You can then use something like the following in your numberOfRowsInSection:
// Customize the number of rows in the table view.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if(tableView == self.searchDisplayController.searchResultsTableView){
// search view population
return [self.filteredList count];
} else {
return [[self.sectionedList objectAtIndex:section] count];
}
}

iOS 5: numberOfRowsInSection doesn't work

I've got a tableView in storybord and UISegmentedControl to populate the over mentioned table with with different data and different design. My problem is that numberOfRowsInSection meth doesn't react when I switch UISegmentedControl.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if(self.segment.selectedSegmentIndex==0)
{
return [self.items count];
NSLog(#"Nominals: %d",self.items.count);
}
if(self.segment.selectedSegmentIndex==1)
{
return [self.coinageArr count];
NSLog(#"Coinage: %d",self.coinageArr.count);
}
//return 0; Complains about no return.
}
Well, NSLogs do not work while navigating. And how to return NSInteger in this case?
Thanx in advance.
EDIT: For shannoga
segment controller switch method:
-(IBAction)segmentValueChaged:(id)sender
{
switch (self.segment.selectedSegmentIndex)
{
case 0:
{
DBAccess *access=[[DBAccess alloc]init];
self.items=[access returnNominals:self.entityID nk:fromPeriod];
[access closeDataBase];
self.tableView.hidden=NO;
[self.tableView reloadData];
break;
}
case 1:
{
DBAccess *access=[[DBAccess alloc]init];
self.coinageArr=[access returnCoinage:fromPeriod period:self.entityID];
self.tableView.hidden=NO;
[self.tableView reloadData];
break;
}
}
}
The NSLog won't work because the return take effect before you get to this line and it will never be executed.
Change it to:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if(self.segment.selectedSegmentIndex==0)
{
NSLog(#"Nominals: %d",self.items.count);
return [self.items count];
}
if(self.segment.selectedSegmentIndex==1)
{
NSLog(#"Coinage: %d",self.coinageArr.count);
return [self.coinageArr count];
}
//return 0; Complains about no return.
}
Can you show the method that you call when the UISegmentedControl is changed?
Pay attention that you don't need to set 2 if statements you could use else.
As #Ryan said you should use [tableview reloadData] on your UISegmentedControl change. Then it will be better if you change the self.items array in your valueChanged method and leave the numberOfRowsInSection with out a change so it will look like that:
- (void)valueChanged:(id)sender
{
if(self.segment.selectedSegmentIndex==0)
{
self.items = what ever
}else{
self.items = what ever
}
[tableview reloadData];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return [self.items count];
}
Good Luck
After you change the value of the UISegmentedControl you need to update the table. You can do it easily with [tableView reloadData]; or you can use something like [tableView reloadSection:0 withTableViewAnimation:UITableViewRowAnimationAutomatic];
The best place to do this is probably in a valueChanged method for your control.
// Wherever you init your UISegmentedControl
segmentedControl addTarget:self selector:#selector(valueChanged:) forEvent:UIControlEventValueChanged];
- (void)valueChanged:(id)sender
{
[tableview reloadData];
}

Resources