UITableViewをツリー上に表示する。第4回目(ツリーの開閉、セルの選択)

前回までで表示部分はだいたい完成したので、今回は動きの部分を実装していきます。
動きとして実装したいのは

  • セクション選択時に、セクションが開閉する。
  • セルを複数選択可能にする。



まず、セクション選択時の動きですが、セクションが選択されたことを検出し、閉じる動作(配下の非表示)を行わなければなりません。セクション選択の検出は、今回はデリゲートで実装します。
新しくSectionHeaderDelegateプロトコルを作成します。ようはインターフェースを定義したヘッダーファイルです。

#import <Foundation/Foundation.h>

@protocol SectionHeaderDelegate <NSObject>
@optional
-(void)sectionSelected:(int)sectionNo;
@end



次に、委譲もとの実装をしていきます。
SectionHeaderを次のように修正します。さきほど作成したSectionHeaderDelegate.hのインポート、デリゲートメソッドを実装する移譲先のクラスへの参照を保持するdelegate_メンバ変数。またその変数にアクセスするためのプロパティ定義を行います。
また、implementationにtouchesBeganメソッドを追加し、デリゲートメソッドを呼び出す実装を記述します。

#import <UIKit/UIKit.h>
#import "SectionHeaderDelegate.h"

@interface SectionHeader : UIView {
@private
    UILabel* sectionNameLabel_;
    UIImageView* switchIcon_;
    UIImage* openImage_;
    UIImage* closeImage_;
    
    __weak NSObject<SectionHeaderDelegate>* delegate_; //ココ
}
@property(nonatomic) int sectionNo;
@property(weak, nonatomic) NSObject<SectionHeaderDelegate>* delegate; //ココ
@property(strong, nonatomic, setter=setSectionName:) NSString* sectionName;
@property(nonatomic, setter=setSectionOpend:) bool sectionOpend;

@end

@implementation SectionHeader
@synthesize sectionNo = sectionNo_;
@synthesize delegate  = delegate_; //ココ

- (id)initWithFrame:(CGRect)frame
{
 ・
 ・
 ・
#pragma mark -
#pragma mark SectionHeaderDelegate
#pragma mark -

//ココ
- (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event {
    if (delegate_ != nil) {
        if ([delegate_ conformsToProtocol:@protocol(SectionHeaderDelegate)]) {
            if ([delegate_ respondsToSelector:@selector(sectionSelected:)]) {
                [delegate_ sectionSelected:sectionNo_];
            }
        }
    }
}
@end



これでセクションがタッチされた時に、メソッドを呼ぶ準備ができました。委譲先となるTreeTableViewController側にタッチされた時の動作を記述します。

#import <UIKit/UIKit.h>
#import "SectionHeaderDelegate.h" // ココ

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

@end

@implementation TreeTableViewController
 ・
 ・
 ・
- (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;
    sectionView.delegate = self; // ココ
    
    return sectionView;
}
 ・
 ・
 ・
#pragma mark -
#pragma mark CustomSectionViewDelegate
#pragma mark -

// ココ
-(void)sectionSelected:(int)sectionNo {
    Animals *section = [dataSource_ objectAtIndex:sectionNo];
    section.openFlag = !section.openFlag;
    
    [self.tableView reloadData];
}



この状態で動かしてみます、セクションをタッチすると開閉するようになりました。だいだい目指すべきことはできましたが、おまけでセルの選択をできるようにしておきます。allowsMultipleSelectionを独自実装します。

#pragma mark - Table view delegate


- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    // データソースより、そのセルに該当するデータを取得
    Animals *section = [dataSource_ objectAtIndex:indexPath.section];
    CreatureType *row = [section.types objectAtIndex:indexPath.row];
    
    // 選択された行の選択をON/OFF反転
    row.selected = !row.selected;

    [tableView reloadData];
}

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
    // データソースより、そのセルに該当するデータを取得
    Animals *section = [dataSource_ objectAtIndex:indexPath.section];
    CreatureType *row = [section.types objectAtIndex:indexPath.row];

    // 行の選択色変更
    ((CustomCell*)cell).cellSelected = row.selected;
}

これで、複数選択できるようになりました。

動きなど基本的な部分はこれで完成です。次回で最終回、見栄えを整えて完成といたします。