UITableViewをツリー上に表示する。第3回目(UI部品をUITableViewに組み込み)

ツリーテーブルの3回目。今回は、本体の部分であるUITableViewを作成していきます。
本体となる、TreeTableViewControllerを作成します、基底クラスにUITableViewControlerを指定します。また、表示するデータを保持するメンバ変数として、データソース(dataSource_)を定義して、そのプロパティ(セッター)も定義しておきます。(必要なヘッダーもimportしておく)

#import <UIKit/UIKit.h>
#import "Animals.h"
#import "CreatureType.h"
#import "PageHeader.h"
#import "SectionHeader.h"
#import "CustomCell.h"


@interface TreeTableViewController : UITableViewController {
@private
    // Data Source
    NSMutableArray* dataSource_;
}
@property(strong, nonatomic, setter=setDataSource:) NSMutableArray* dataSource;

@end

@implementation TreeTableViewController
@synthesize dataSource = dataSource_;

- (id)initWithStyle:(UITableViewStyle)style
 ・
 ・
 ・



次に、これを起動時に表示するように次のように修正します。2012-08--11の記事から、次のように書き換えます。AppDelegate.mでセットされるrootViewControlerをTreeTableViewControllerに変更します。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    // Override point for customization after application launch.
    self.viewController = [[TreeTableViewController alloc] init];

    self.window.rootViewController = self.viewController;
    [self.window makeKeyAndVisible];
    return YES;
}



これで起動すると、何もないテーブルが表示されるはずです。



次にデータソースのデリゲートを実装していきます。
セクションの数を返すメソッド、セクション内の行数を返すメソッドを次のように作成します。

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    // Return the number of sections.
    if (dataSource_) {
        return [dataSource_ count];
    } else {
        return 0;
    }
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)sectionNumber
{
    // Return the number of rows in the section.
    if (dataSource_) {
        Animals *section = [dataSource_ objectAtIndex:sectionNumber];
        if (section.openFlag) {
            return [section.types count];
        } else {
            return 0;
        }
    } else {
        return 0;
    }
}



次にツリーの親、セクションヘッダーを表示するデリゲートメソッドのviewForHeaderInSectionを作ります。ここで、セクションに表示するUIViewをreturnすることで、セクションにそのUIViewを表示することができます。sectionNumが引数で渡されますので、データソースよりセクション番号にあった値を取り出し表示してあげます。

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)sectionNum {
    Animals *section = [dataSource_ objectAtIndex:sectionNum];
    
    // カスタムセクションの作成
    SectionHeader *sectionView = [[SectionHeader alloc]
                           initWithFrame:CGRectMake(0,
                                                    0,
                                                    self.tableView.frame.size.width,
                                                    50)];
    sectionView.sectionNo = sectionNum;
    sectionView.sectionName = section.sectionName;
    sectionView.sectionOpend = section.openFlag;
    
    return sectionView;
}

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
    return 50;
}



ツリーの子、カスタムセルを表示するデリゲートメソッドのcellForRowAtIndexPathを作ります。indexPathが引数で渡されますので、データソースより行番号にあった値を取り出し表示してあげます。

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell;
    
    // Data Sourceより該当行の値をとりだし
    Animals *section = [dataSource_ objectAtIndex:indexPath.section];
    CreatureType *row = [section.types objectAtIndex:indexPath.row];
    
    // カスタムセルの作成
    cell = [tableView dequeueReusableCellWithIdentifier:@"custum"];
    if (cell == nil) {
        cell = [[CustomCell alloc] initWithStyle:UITableViewCellStyleDefault
                                 reuseIdentifier:@"custum"];
        cell.frame = CGRectMake(0, 0, self.tableView.frame.size.width, 50.0);
    }
    
    // 名前
    ((CustomCell*)cell).cellName = row.typeName;
    
    // 選択状態
    ((CustomCell*)cell).cellSelected = row.selected;
    
	return cell;
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
	return 50.0;
}



おまけにページヘッダーを表示します。TreeTableViewControllerのinitWithStyleメソッドに、ページヘッダーの作成を追加します。

@implementation TreeTableViewController
@synthesize dataSource = dataSource_;

- (id)initWithStyle:(UITableViewStyle)style
{
    self = [super initWithStyle:style];
    if (self) {
        // ページヘッダー
        PageHeader *headerView = [[PageHeader alloc] initWithFrame:CGRectMake(0,
                                                                          0,
                                                                          self.tableView.frame.size.width,
                                                                          50)];
        headerView.titleName = @"動物";
        self.tableView.tableHeaderView  = headerView;
    }
    return self;
}



これで表示の準備ができましたので、テストデータを作成して動かしてみます。テストデータはとりあえず、AppDelegateで作成してTreeTableViewControllerのdataSourceプロパティにセットします。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    // Override point for customization after application launch.
    self.viewController = [[TreeTableViewController alloc] init];
    
    // テストデータ
    NSMutableArray *sections = [[NSMutableArray alloc] init];
    NSMutableArray *rows1 = [[NSMutableArray alloc] initWithObjects:
                             [[CreatureType alloc] initWithTypeName:@"犬" selected:false],
                             [[CreatureType alloc] initWithTypeName:@"ネコ" selected:false],
                             [[CreatureType alloc] initWithTypeName:@"ジャンクロードバンダム" selected:false],
                             nil];
    [sections addObject:[[Animals alloc] initWithSectionName:@"ほ乳類"
                                                    openFlag:true
                                                       types:rows1]];
    NSMutableArray *rows2 = [[NSMutableArray alloc] initWithObjects:
                             [[CreatureType alloc] initWithTypeName:@"さんま" selected:false],
                             [[CreatureType alloc] initWithTypeName:@"マグロ" selected:false],
                             [[CreatureType alloc] initWithTypeName:@"白星姫" selected:false],
                             nil];
    [sections addObject:[[Animals alloc] initWithSectionName:@"魚類"
                                                    openFlag:true
                                                       types:rows2]];
    self.viewController.dataSource = sections;

    self.window.rootViewController = self.viewController;
    [self.window makeKeyAndVisible];
    return YES;
}



起動してみると、このように表示されるはずです。

今回はここまで、次回はセクション選択時に開閉するような動きを実装していきます。