11.05.2012

Xcode 4, iPhone, Cocoa Touch, iOS4, iOS5

Tutorial: UITableViewController mit Sections

In diesem Tutorial wird erklärt, wie mit einem UITableViewController eine TableView erstellt wird, die verschiedene Sektionen hat. In dem Beispiel werden alle Font-Typen, die auf dem iPhone vorhanden sind, in der UITableView angezeigt. Sie sind jeweils nach ihnen Font-Familien in Sektionen aufgeteilt. Außerdem wird der Unterschied zwischen UITableViewStyleGrouped und UITableViewStylePlan erklärt.

Dieses Tutorial erweitert das Beispiel aus Tutorial: UITableViewController. Die fertige App wird so aussehen (links: UITableViewStylePlan; rechts:UITableViewStyleGrouped)

Als erste muß das FontModel angepaßt werden. Dazu wird in der Header-Datei folgendes geändert:

//
//  FontModel.h
//  TableViewApp
//
//  Created by Jörn Hameister on 11.05.12.
//  Copyright (c) 2012 http://www.hameister.org. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface FontModel : NSObject 

//-(int)countFonts;
//-(NSString*)fontNameAtIndex:(int)index;

-(NSArray*) families;
-(int)numberOfFontsForFamily:(int) sectionIndex;
-(NSString*) fontNameAtIndex:(int)fontIndex inFamily:(int)familyIndex;

@end

Die beiden Methoden aus dem Tutorial: UITableViewController werden nicht mehr benötigt. Dafür brauchen wir aber eine Methode zum Abfragen aller Font-Familien (families), um die Namen für die Sektionen zu bestimmen. Außerdem wird eine Methode benötigt, die die Anzahl der Fonts für eine Familie zurückliefert (numberOfFontsForFamily:. Sie wird dazu verwendet, um die Anzahl der Zeilen innerhalb einer Sektion zu berechnen. Die letzte Methode liefert den Font-Namen zurück.

Die Implementierungen für diese Methoden werden in der Datei FontModel.m ergänzt. Wie schon in der Header-Datei, sind einge Dinge überflüssig geworden und sind in dem folgenden Programmcode auskommentiert. Unter anderem werden die Fonts nicht mehr in einer Liste fontList verwaltet, wodurch sowohl der getter fontModel, als auch die init-Methode nicht mehr benötigt werden.

//
//  FontModel.m
//  TableViewApp
//
//  Created by Jörn Hameister on 11.05.12.
//  Copyright (c) 2012 http://www.hameister.org. All rights reserved.
//

#import "FontModel.h"

//@interface FontModel ()
//    @property (nonatomic, strong) NSMutableArray* fontList;
//@end

@implementation FontModel
//@synthesize fontList = _fontList;
//
//-(NSMutableArray*) fontList {
//    if(_fontList == nil) {
//        _fontList = [[NSMutableArray alloc] init];
//    }
//    return _fontList;
//}
//
//- (id)init {
//    self = [super init];
//    if(self) {
//        NSArray *families = [UIFont familyNames];
//        for(NSString * family in families) {
//            NSArray *fonts =[UIFont fontNamesForFamilyName:family];
//            for(NSString *font in fonts) {
//                [self.fontList addObject:[font description]];
//            }
//        }
//    }
//    return self;
//}

//-(int)countFonts {
//    return self.fontList.count;
//}
//
//-(NSString*)fontNameAtIndex:(int)index {
//    return [self.fontList objectAtIndex:index];
//}


-(NSArray*) families {
    return [UIFont familyNames];
}

-(int)numberOfFontsForFamily:(int) sectionIndex {
    NSArray *families = [UIFont familyNames];
    NSString* family = [families objectAtIndex:sectionIndex];
    
    NSArray *fonts = [UIFont fontNamesForFamilyName:family];
    return fonts.count;
}

-(NSString*) fontNameAtIndex:(int)fontIndex inFamily:(int)familyIndex {
    NSArray *families = [UIFont familyNames];
    NSString* family = [families objectAtIndex:familyIndex];
    
    NSArray *fonts = [UIFont fontNamesForFamilyName:family];
    return [fonts objectAtIndex:fontIndex];
}

@end

Es ist anzumerken, daß die beiden unteren Methode nur der Verständlichkeit wegen mehrere Zeilen haben. Die folgenden Zeilen haben den gleichen Effekt und sind erheblich kompakter:

-(NSArray*) families {
    return [UIFont familyNames];
}

-(int)numberOfFontsForFamily:(int) sectionIndex {
    return [UIFont fontNamesForFamilyName:[[UIFont familyNames] objectAtIndex:sectionIndex]].count;
}

-(NSString*) fontNameAtIndex:(int)fontIndex inFamily:(int)familyIndex {
    return [[UIFont fontNamesForFamilyName:[[UIFont familyNames] objectAtIndex:familyIndex]] objectAtIndex:fontIndex];
}

In der Datei ViewController.m müssen nur zwei Zeilen ausgetauscht werden.

Zuerst in der Methode tableView:cellForRowAtIndexPath: wo nun die Methode fontNameAtIndex:inFamily: aufgerufen wird, um den Font-Namen zu bestimmen.

Außerdem muß die Methode tableView:numberOfRowsInSection: so angepaßt werden, daß durch dem Aufruf numberOfFontsForFamily: nun die Anzahl der Zeilen in einer Sektion zurückgeliefert werden.

//
//  ViewController.m
//  TableViewApp
//
//  Created by Jörn Hameister on 11.05.12.
//  Copyright (c) 2012 http://www.hameister.org. All rights reserved.
//

#import "ViewController.h"
#import "FontModel.h"

@implementation ViewController
@synthesize model = _model;


-(FontModel*)model {
    if (_model==nil) {
        _model = [[FontModel alloc]init];
    }
    return _model;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    
    UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:@"UITableViewCell"];
    if(!cell) {
        cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"UITableViewCell"];
    }
    
        [[cell textLabel] setText:[self.model fontNameAtIndex:[indexPath row] inFamily:[indexPath section]]];
//    [[cell textLabel] setText:[self.model fontNameAtIndex:[indexPath row]]];
    return cell;
}



- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return self.model.families.count ;
}


- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
    return [self.model.families objectAtIndex:section];
}

-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
//    return self.model.countFonts;
    return [self.model numberOfFontsForFamily:section];
}

@end

Bei einer UITableView stehen die beiden Styles zur Verfügung:

  • UITableViewStyleGrouped
  • UITableViewStylePlain

Wird bei der Initialisierung nichts angegeben, dann wird UITableViewStylePlain verwendet. Wenn für dieses Beispiel der Style umgestellt werden soll, dann muß in der Klasse ViewController eine init-Methode ergänzt werden, die folgendermaßen aussieht:

- (id)init {
  return [super initWithStyle:UITableViewStyleGrouped];
}

Auf diese Weise erhält man eine TableView, wie sie oben rechts abgebildet ist.

Das waren alle Änderungen, die gemacht werden mußten, damit die UITableView Sektionen anzeigt. Nach dem Kompilieren und Starten mit ⌘+R öffnet sich der Simulator und zeigt die angepaßte TableView mit Sektionen an.