Section index in table view - iphone

I am implementing a table index view and amazed to see how my table indexes are working even without implementing:
- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index method.
I have only implemented:
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView
Strangely, when I am running in breakpoints, Once i click on any of the index values my
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
method is getting called.
Any clue why this is so happening and what is the significance of sectionForSectionIndexTitle method then.

if you have a list of all letters in alphabet and your list only contains some entries, you could use the following code:
//Asks the data source to return the index of the section having the given title and section title index.
- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index {
if (tableView == self.searchDisplayController.searchResultsTableView || self.searchBar.text.length > 0)
{
return 0;
}
else
{
//direct - firsttime match
if([self.realMIndexArray containsObject:title]) {
NSInteger count = 0;
for(NSString *character in self.realMIndexArray)
{
if([character isEqualToString:title]){
return count;
}
count ++;
}
}
else {
//take next higher letter from alphabet and check if its contained in the "available letters list"
//if not, select last entry of list
for(int i = [self.indexArray indexOfObject:title] + 1; i < [self.indexArray count]; i++) {
NSString* character = [self.indexArray objectAtIndex:i];
if([self.realMIndexArray containsObject:character]) {
return [self.realMIndexArray indexOfObject:character];
}
}
return [self.realMIndexArray count] - 1;
}
return 0;// in case of some eror donot crash d application
}
}
realMIndexArray count == letters really existing in list
indexArray = list of all letters in alphbeth.
hope this helps someone (took me a little bit of time to figure it out)

Any clue why this is so happening
Yes. When you tap (you do not click on an iPhone) on a table's index, the underlying table view will want to jump to that section, and the cells in that section. In order to do that, it has to ask the data source for those cells so it can render them on the screen.
what is the significance of
sectionForSectionIndexTitle method
then.
The documentation for tableView:sectionForSectionIndexTitle:atIndex: (which is an optional method in the UITableViewDataSource protocol) says:
Asks the data source to return the
index of the section having the given
title and section title index.
and
You implement this method only for
table views with a section index
list—which can only be table views
created in the plain style
(UITableViewStylePlain).
Does this apply for your UITableView? In other words, are you using a grouped table view style?

Related

TableviewCell shows message when no data in table

I am using grouped tableview for developing a contact list using database. I have to show the message "No Contacts" on tableview when there is no contact in list. how can I do it?
Share your ideas..
Thanks in Advance
supposing that you are using an array to store all the contacts then use the following delegate
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// You can also modify this condition according to a specific section
if([YOUR_ARRAY count] == 0)
{
return 1;
}
else
return [YOUR_ARRAY count];
}
Now adding data to table in following delegate
-(UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// Initialise your cell
if([YOUR_ARRAY count] > 0){
// add your array data to cells
}
if([YOUR_ARRAY count] == 0){
// this means no contacts in array and therfore you have only one cell to display NO CONTACTS
}
return cell;
}
For cases like this one we used table headers.
If the table had elements in his data source, the table header was clear and had a 1px height.
If the data source had no elements, then the table header view was set as big as the table's frame and contained a message, an image or whatever you might need.
The functions (table view delegate methods, actually) we used were height for header in section and view for header in section. We verified the data source inside the viewForHeader function
You can achieve the same effect using the table footers as well
you can add UILabel
ande set the text of the label
label.text = #"No results ";
and you make a test
if ([contacts count] == 0)
{
yourTableview.hidden = YES;
yourLabel.hidden = NO;
}
else
{
yourTableview.hidden = NO;
yourLabel.hidden = YES;
}`

custom amount of cells in each tableview group

How would I be able to customize the amount of cells in each tableview group? Basically, I need 2 cells in the first group, 4 cells in the second group, and one cell in the third. I can't seem to find anything, which is odd, unless I'm calling it the wrong thing. Thanks in advance. :)
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (section == 0)
return 2;
else if (section == 1)
return 4;
else if (section == 2)
return 1;
}
Number of cells in each table section is specified in table's data source tableView:numberOfRowsInSection: method. Somewhat dummy example for your case:
- (int) numberOfSectionsInTableView:(UITableView*)tableView{
return 3;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
int numbers[] = {2,4,1};
return numbers[section];
}

UITableView Section Header issue

All,
I have a grouped UITableView with a possible total of 3 sections. There could be 1, 2 or 3.
My issue is that for each section I use a different header & footer view. I am choosing which header/footer to show by checking the section #.
This obviously does not work, as section 0 does not always represent what 'header' 0 shows.
Example:
Header #0 = "Game in progress". But no games in progress are returned from the database. Only 'Games Ended" exist. Therefore section 0 would be all 'games ended'. I don't want 'Games Ended' to use the 'Games in Progress' header.
I can't find a way to check the section value, and not the number.
To put it simply, I would like to be able to show section header #3 for section name #3, even if section name #3 is section #0.
I know this seems trivial, and is probably simple... but I am stuck. Any help is appreciated.
Thanks.
----- CODE -----
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return [[fetchedResultsController_ sections] count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
id <NSFetchedResultsSectionInfo> sectionInfo = [[fetchedResultsController_ sections] objectAtIndex:section];
return [sectionInfo numberOfObjects];
}
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
if(section == 0)
{
return 50.0f;
}
else if (section == 1)
return 50.0f;
else
return 50.0f;
}
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
if(section == 0 )
{
return 50.0f;
}
else if (section == 1)
return 5.0f;
else
return 80.0f;
}
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
if(section == 0)
{
return headerView1;
}
else if (section == 1)
return headerView2;
else
return headerView3;
}
- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section {
if(section == 0)
{
return footerView1;
}
else if (section == 1)
return footerView2;
else
return footerView3;
}
Obviously, deciding which header / footer to show by checking the section # is wrong (this is bad MVC). For a solution to your problem, it would be better to see some actual code, although I think I can suggest something in general:
The sections that you show are taken out of some data source - an array, a dictionary or some other collection (this is the same collection you use to determine, for example, the return value for the numberOfSectionsInTableView: delegate method. If you haven't done so already, you should incorporate these data instances into some object that contains the data itself (this is the data that you normally need for displaying the cell/header/footer elements along with the actual data values) - In this object, add an additional "HeaderType" enumerated value, so that each object "knows" how it is supposed to be displayed. This way your MVC is perfect: You have your data stored in a collection of custom objects, your controller knows how to display the data by it's type and of course your view shows the data properly based on the controller's instructions.
Here is an example of an enumeration that could help:
typedef enum {
kHeaderTypeGameProgress,
kHeaderTypeGameStats,
kHeaderTypeGameDate
} HeaderType;
In your "viewForHeader" or "viewForFooter" methods, just add a switch type to check the data's HeaderType and create a view accordingly. Hope I helped, good luck!
It seems that in your cellForRowAtIndexPath, you must already have some logic that decides what group to show data from, maybe something like:
NSArray *group;
int section = indexPath.section;
if (![gamesInProgress count]) section++;
switch (section) {
case 0:
group = gamesInProgress;
break;
case 1:
group = finishedGames;
break;
// etc.
}
In your viewForHeaderInSection, write similar code that sets a NSString instead of NSArray.

iPhone UITableView Nested Sections

For the acani iPhone app, I'd like display groups (based on interests) in a UITableView. I'd like to organize the groups taxonomically, e.g.:
Sports
Bat-and-ball
Baseball
Softball
Cricket
Hockey
Field Hockey
Ice Hockey
Roller Hockey
Engineering
Electrical Engineering
Biochemical Engineering
How should I arrange this on a UITableView?
I'm thinking that there should be a root UITableView that will have the sections Sports & Engineering, and the cells Bat-and-ball & Hockey will be under the Sports section, and the cells Electrical Engineering & Biochemical Engineering will be under the Engineering section.
Then Bat-and-ball should have its own UITableView, which should have cells Baseball, Softball, and Cricket.
Does this sound like a good way to arrange the UI?
Do you have any sample code or links to Xcode sample code for a UI like this? There's gotta be an Xcode sample project that does something like this. Perhaps the periodic table of elements project or Core Data Books?
Thanks!
Matt
You got it. A UITableView really isn't designed to show more than two levels of a hierarchy, as sections and rows. If you want to show more than two levels, a "drill-down" approach used in most (all?) iOS apps, where tapping a row presents another UITableView on the navigation stack. (As you say.)
There are lots of Apple sample code projects that use this design pattern.
Edit: just checked and DrillDownSave is a good example, as is SimpleDrillDown.
The trick to have nested sections is to have two kinds of rows in the table view. One to represent the second level of sections and another to represent the normal rows in the tableview. Let's say you have a two level array (say sections) to represent the items in your table view.
Then, the total number of sections that we have are just the number of top level sections. The number of rows in each top level section would be the number of subsections + the number of rows in each subsection.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return self.sections.count;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    NSArray *sectionItems = self.sections[(NSUInteger) section];
    NSUInteger numberOfRows = sectionItems.count; // For second level section headers
    for (NSArray *rowItems  in sectionItems) {
        numberOfRows += rowItems.count; // For actual table rows
    }
    return numberOfRows;
}
Now, all we need to think about is how to create the rows for the table view. Set up two prototypes in the storyboard with different reuse identifiers, one for the section header and another for row item and just instantiate the correct one based on the asked index in the data source method.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    NSMutableArray *sectionItems = self.sections[(NSUInteger) indexPath.section];
    NSMutableArray *sectionHeaders = self.sectionHeaders[(NSUInteger) indexPath.section];
    NSIndexPath *itemAndSubsectionIndex = [self computeItemAndSubsectionIndexForIndexPath:indexPath];
    NSUInteger subsectionIndex = (NSUInteger) itemAndSubsectionIndex.section;
    NSInteger itemIndex = itemAndSubsectionIndex.row;
    if (itemIndex < 0) {
        // Section header
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"SECTION_HEADER_CELL" forIndexPath:indexPath];
        cell.textLabel.text = sectionHeaders[subsectionIndex];
        return cell;
    } else {
        // Row Item
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"ROW_CONTENT_CELL" forIndexPath:indexPath];
        cell.textLabel.text = sectionItems[subsectionIndex][itemIndex];
        return cell;
    }
}
- (NSIndexPath *)computeItemAndSubsectionIndexForIndexPath:(NSIndexPath *)indexPath {
    NSMutableArray *sectionItems = self.sections[(NSUInteger) indexPath.section];
    NSInteger itemIndex = indexPath.row;
    NSUInteger subsectionIndex = 0;
    for (NSUInteger i = 0; i < sectionItems.count; ++i) {
        // First row for each section item is header
        --itemIndex;
        // Check if the item index is within this subsection's items
        NSArray *subsectionItems = sectionItems[i];
        if (itemIndex < (NSInteger) subsectionItems.count) {
            subsectionIndex = i;
            break;
        } else {
            itemIndex -= subsectionItems.count;
        }
    }
    return [NSIndexPath indexPathForRow:itemIndex inSection:subsectionIndex];
}
Here's a detailed post on how to do this.

sectionIndexTitlesForTableView line up correctly with sections

I've got a table view with many sections, the title for these sections is just A-Z and # just like in the iPhone address book App. I have implemented sectionIndexTitlesForTableView to have the quick move to particular letter and basically just return an array of Letters A - Z and #.
This would work if my list always contains an item for every letter of the alphabet but it won't and this screws up the section index titles because hitting C in the list might go to D if the 3th section is D (ie if there is nothing in section C).
I know I could return the array in sectionIndexTitlesForTableView with only the letters that are sections but this would look a bit odd and not the same functionality as the iPhone Address book app.
How can I rectify this?
I don't see how #Rudiger's method would work if you have only have sections A, C, F, S, T and section index titles for A-Z. Such a situation might arise when using MPMediaQuery.
To get around this I've implemented this method as follows, the tableview will scroll to the correct section or the next if the one you are looking for doesn't exist.
- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index
{
NSString *sectionTitle = nil;
NSComparisonResult result;
int i;
for(i = 0; i < tableView.numberOfSections; i++)
{
sectionTitle = [self tableView:tableView titleForHeaderInSection:i];
result = [title compare:sectionTitle];
if(result != NSOrderedDescending)
break;
}
return (MIN (i, (tableView.numberOfSections - 1)));
}
UPDATE
Changed the return value to fix the situation described by Eric D'Souza.
Basically you have to implement:
- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index {
return [sections indexOfObject:title];
}
and return based on the index and title what section it should be on. Where sections is the array storing the list of sections